Skip to content

Commit

Permalink
refactor(logging): ♻️ further logging improvements
Browse files Browse the repository at this point in the history
- use slogtint for console and regular slog for log file
- additional colorisation for console
  • Loading branch information
joshuar committed Oct 4, 2024
1 parent fe70940 commit 29b6fc1
Showing 1 changed file with 52 additions and 19 deletions.
71 changes: 52 additions & 19 deletions internal/logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"log/slog"
"os"
"path/filepath"
"time"

slogmulti "github.com/samber/slog-multi"

Expand Down Expand Up @@ -44,7 +45,7 @@ func New(appID string, options Options) *slog.Logger {
var (
logLevel slog.Level
logFile string
handler slog.Handler
handlers []slog.Handler
)

// Set the log level.
Expand All @@ -64,7 +65,9 @@ func New(appID string, options Options) *slog.Logger {
logFile = filepath.Join(xdg.ConfigHome, appID, logFileName)
}

// Set the slog handler
handlers = append(handlers, tint.NewHandler(os.Stderr,
generateConsoleOptions(logLevel, os.Stderr.Fd())))

// Unless no log file was requested, set up file logging.
if logFile != "" {
logFH, err := openLogFile(logFile)
Expand All @@ -73,27 +76,34 @@ func New(appID string, options Options) *slog.Logger {
slog.String("file", logFile),
slog.Any("error", err))
} else {
handler = slogmulti.Fanout(
tint.NewHandler(os.Stdout, generateOptions(logLevel, os.Stdout.Fd())),
tint.NewHandler(logFH, generateOptions(logLevel, logFH.Fd())),
)
handlers = append(handlers, slog.NewTextHandler(logFH, generateFileOpts(logLevel)))
}
} else {
handler = slogmulti.Fanout(
tint.NewHandler(os.Stdout, generateOptions(logLevel, os.Stdout.Fd())),
)
}

logger := slog.New(handler)
logger := slog.New(slogmulti.Fanout(handlers...))
slog.SetDefault(logger)

return logger
}

func generateOptions(level slog.Level, fd uintptr) *tint.Options {
func generateConsoleOptions(level slog.Level, fd uintptr) *tint.Options {
opts := &tint.Options{
Level: level,
NoColor: !isatty.IsTerminal(fd),
Level: level,
NoColor: !isatty.IsTerminal(fd),
ReplaceAttr: tintLevelReplacer,
TimeFormat: time.Kitchen,
}
if level == LevelTrace {
opts.AddSource = true
}

return opts
}

func generateFileOpts(level slog.Level) *slog.HandlerOptions {
opts := &slog.HandlerOptions{
Level: level,
ReplaceAttr: fileLevelReplacer,
}
if level == LevelTrace {
opts.AddSource = true
Expand All @@ -102,20 +112,43 @@ func generateOptions(level slog.Level, fd uintptr) *tint.Options {
return opts
}

//nolint:unused
func levelReplacer(_ []string, attr slog.Attr) slog.Attr {
func tintLevelReplacer(_ []string, attr slog.Attr) slog.Attr {
// Set default level.
if attr.Key == slog.LevelKey {
level, ok := attr.Value.Any().(slog.Level)
if !ok {
level = slog.LevelInfo
}

// Errors in red.
if err, ok := attr.Value.Any().(error); ok {
aErr := tint.Err(err)
attr.Key = aErr.Key
}

// Format custom log level.
levelLabel, exists := LevelNames[level]
if !exists {
levelLabel = level.String()
if exists {
attr.Value = slog.StringValue(levelLabel)
}
}

return attr
}

func fileLevelReplacer(_ []string, attr slog.Attr) slog.Attr {
// Set default level.
if attr.Key == slog.LevelKey {
level, ok := attr.Value.Any().(slog.Level)
if !ok {
level = slog.LevelInfo
}

attr.Value = slog.StringValue(levelLabel)
// Format custom log level.
levelLabel, exists := LevelNames[level]
if exists {
attr.Value = slog.StringValue(levelLabel)
}
}

return attr
Expand Down

0 comments on commit 29b6fc1

Please sign in to comment.