Skip to content

Commit

Permalink
feat: themes support for logger
Browse files Browse the repository at this point in the history
- migrated to `github.com/phuslu/log` from `github.com/charmbracelet/log`, not much of a reason just for trying out custom formatting
  • Loading branch information
nxtcoder17 committed Oct 19, 2024
1 parent 8ccec65 commit 9116b0f
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 49 deletions.
123 changes: 74 additions & 49 deletions pkg/logging/logger.go
Original file line number Diff line number Diff line change
@@ -1,81 +1,106 @@
package logging

import (
"fmt"
"io"
"log/slog"
"os"

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/log"
"github.com/phuslu/log"
)

type SlogOptions struct {
Writer io.Writer
type Options struct {
Prefix string
Writer io.Writer

Theme *Theme

ShowTimestamp bool
ShowCaller bool
ShowDebugLogs bool
ShowLogLevel bool

SetAsDefaultLogger bool
}

func NewSlogLogger(opts SlogOptions) *slog.Logger {
// INFO: force colored output, otherwise honor the env-var `CLICOLOR_FORCE`
if _, ok := os.LookupEnv("CLICOLOR_FORCE"); !ok {
os.Setenv("CLICOLOR_FORCE", "1")
}
// PickPrefix func() string
SlogKeyAsPrefix string

// constants
keyValueSeparator string
}

func (opts Options) WithDefaults() Options {
if opts.Writer == nil {
opts.Writer = os.Stderr
}

level := log.InfoLevel
if opts.ShowDebugLogs {
level = log.DebugLevel
if opts.Theme == nil {
opts.Theme = DefaultTheme()
}

logger := log.NewWithOptions(opts.Writer, log.Options{
ReportCaller: opts.ShowCaller,
ReportTimestamp: opts.ShowTimestamp,
Prefix: opts.Prefix,
Level: level,
})

styles := log.DefaultStyles()
// styles.Caller = lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Dark: "#5b717f", Light: "#36cbfa"}).Faint(true)
styles.Caller = lipgloss.NewStyle().Foreground(lipgloss.Color("#878a8a"))

styles.Levels[log.ErrorLevel] = lipgloss.NewStyle().
SetString("ERROR").
Padding(0, 1, 0, 1).
// Background(lipgloss.Color("204")).
Foreground(lipgloss.Color("202"))

styles.Levels[log.DebugLevel] = styles.Levels[log.DebugLevel].Foreground(lipgloss.Color("#5b717f"))

styles.Levels[log.InfoLevel] = styles.Levels[log.InfoLevel].Foreground(lipgloss.Color("#36cbfa"))

// BUG: due to a bug in termenv, adaptive colors don't work within tmux
// it always selects the dark variant

// styles.Levels[log.InfoLevel] = styles.Levels[log.InfoLevel].Foreground(lipgloss.AdaptiveColor{
// Light: string(lipgloss.Color("#36cbfa")),
// Dark: string(lipgloss.Color("#608798")),
// })
if opts.keyValueSeparator == "" {
opts.keyValueSeparator = "="
}

styles.Key = lipgloss.NewStyle().Foreground(lipgloss.Color("#36cbfa")).Bold(true)
return opts
}

logger.SetStyles(styles)
func New(opts Options) *slog.Logger {
opts = opts.WithDefaults()

// output := termenv.NewOutput(os.Stdout, termenv.WithProfile(termenv.TrueColor))
// logger.Info("theme", "fg", output.ForegroundColor(), "bg", output.BackgroundColor(), "has-dark", output.HasDarkBackground())
writePrefix := func(w io.Writer, args *log.FormatterArgs) {
if opts.Prefix != "" {
fmt.Fprintf(w, "%s ", opts.Theme.TaskPrefixStyle.Render(opts.Prefix))
}

l := slog.New(logger)
for i := range args.KeyValues {
if args.KeyValues[i].Key == opts.SlogKeyAsPrefix {
fmt.Fprintf(w, "%s ", opts.Theme.LogLevelStyles[ParseLogLevel(args.Level)].Render(fmt.Sprintf("[%s]", args.KeyValues[i].Value)))
break
}
}
}

l := log.Logger{
Level: func() log.Level {
if opts.ShowDebugLogs {
return log.DebugLevel
}
return log.InfoLevel
}(),
Caller: func() int {
if opts.ShowCaller {
return 1
}
return 0
}(),
// Context: []byte{},
Writer: &log.ConsoleWriter{
ColorOutput: false,
QuoteString: true,
EndWithMessage: true,
Formatter: func(w io.Writer, args *log.FormatterArgs) (int, error) {
writePrefix(w, args)

if opts.ShowLogLevel {
fmt.Fprintf(w, "%s ", opts.Theme.LogLevelStyles[ParseLogLevel(args.Level)].Render(args.Level))
}

fmt.Fprint(w, opts.Theme.MessageStyle.Render(args.Message))
for i := range args.KeyValues {
if args.KeyValues[i].Key == opts.SlogKeyAsPrefix {
continue
}
fmt.Fprintf(w, " %s%s%v", opts.Theme.SlogKeyStyle.Render(args.KeyValues[i].Key), opts.Theme.SlogKeyStyle.Faint(true).Render(opts.keyValueSeparator), opts.Theme.MessageStyle.Render(args.KeyValues[i].Value))
}

return fmt.Fprintf(w, "\n")
},
},
}
sl := l.Slog()
if opts.SetAsDefaultLogger {
slog.SetDefault(l)
slog.SetDefault(sl)
}

return l
return sl
}
99 changes: 99 additions & 0 deletions pkg/logging/theme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package logging

import (
"os"

"github.com/charmbracelet/lipgloss"
)

type LogLevelStyle int

const (
LogLevelTrace LogLevelStyle = 0
LogLevelDebug LogLevelStyle = 1
LogLevelInfo LogLevelStyle = 2
LogLevelWarn LogLevelStyle = 3
LogLevelError LogLevelStyle = 4

LogLevelUnknown LogLevelStyle = 5
)

func ParseLogLevel(level string) int {
switch level {
case "trace":
return 0
case "debug":
return 1
case "info":
return 2
case "warn":
return 3
case "error":
return 4
default:
return 5
}
}

type Theme struct {
TaskPrefixStyle lipgloss.Style
MessageStyle lipgloss.Style
SlogKeyStyle lipgloss.Style

// Styles are in order, TRACE,DEBUG,INFO,WARN,ERROR
LogLevelStyles [6]lipgloss.Style

LogLevelDebugStyle lipgloss.Style
LogLevelInfoStyle lipgloss.Style
LogLevelErrorStyle lipgloss.Style
}

func DefaultTheme() *Theme {
if os.Getenv("RUNFILE_THEME") == "light" {
fg := lipgloss.Color("#4a84ad")
bg := lipgloss.Color("#f4f7fb")

style := lipgloss.NewStyle().Background(bg).Foreground(fg)

return &Theme{
TaskPrefixStyle: style,
SlogKeyStyle: style.Bold(true),
MessageStyle: style.UnsetBackground().Foreground(lipgloss.Color("#6d787d")),
LogLevelStyles: [6]lipgloss.Style{
style.Foreground(lipgloss.Color("#bdbfbe")).Faint(true), // TRACE
style.Foreground(lipgloss.Color("#bdbfbe")).Faint(true), // DEBUG
style.UnsetBackground().Foreground(lipgloss.Color("#099dd6")).Faint(true), // INFO
style.UnsetBackground().Foreground(lipgloss.Color("#d6d609")).Faint(true), // WARN
style.UnsetBackground().Foreground(lipgloss.Color("#c76975")), // ERROR
style.UnsetBackground().Foreground(lipgloss.Color("#d6d609")).Bold(true), // UNKNOWN
},
}
}

fg := lipgloss.Color("#9addfc")
// bg := lipgloss.Color("#172830")

style := lipgloss.NewStyle().Foreground(fg)

return &Theme{
TaskPrefixStyle: style.Faint(true),
// SlogKeyStyle: style.UnsetBackground().Foreground(lipgloss.Color("#8f8ad4")),
// SlogKeyStyle: style.UnsetBackground().Foreground(lipgloss.Color("#75b9ba")),
// MessageStyle: style.UnsetBackground().Foreground(lipgloss.Color("#e6e8ed")).Faint(true),
// MessageStyle: style.UnsetBackground().Foreground(lipgloss.Color("#e6e8ed")).Faint(true),
MessageStyle: style.UnsetBackground().Foreground(lipgloss.Color("#bdbfbe")),
// SlogKeyStyle: style.UnsetBackground().Foreground(lipgloss.Color("#2fbaf5")),
SlogKeyStyle: style.UnsetBackground().Foreground(lipgloss.Color("#85d3d4")),
LogLevelDebugStyle: style.Foreground(lipgloss.Color("#bdbfbe")).Faint(true),
LogLevelInfoStyle: style.Foreground(lipgloss.Color("#099dd6")),
LogLevelErrorStyle: style.Foreground(lipgloss.Color("#c76975")),
LogLevelStyles: [6]lipgloss.Style{
style.Foreground(lipgloss.Color("#bdbfbe")).Faint(true), // TRACE
style.Foreground(lipgloss.Color("#bdbfbe")).Faint(true), // DEBUG
style.Foreground(lipgloss.Color("#099dd6")), // INFO
style.UnsetBackground().Foreground(lipgloss.Color("#d6d609")).Faint(true), // WARN
style.Foreground(lipgloss.Color("#c76975")), // ERROR
style.UnsetBackground().Foreground(lipgloss.Color("#d6d609")).Bold(true), // UNKNOWN
},
}
}

0 comments on commit 9116b0f

Please sign in to comment.