Skip to content

Instantly share code, notes, and snippets.

@mdwhatcott
Last active December 14, 2022 16:34
Show Gist options
  • Save mdwhatcott/b05d2c0223905b32af7310ac7a6aa8cf to your computer and use it in GitHub Desktop.
Save mdwhatcott/b05d2c0223905b32af7310ac7a6aa8cf to your computer and use it in GitHub Desktop.
Configuring a slog handler with functional options
package slogging
import (
"path/filepath"
"strings"
"golang.org/x/exp/slog"
)
type source int
const (
SourceNone source = iota
SourceFile
SourcePath
)
type configuration struct {
source source
stampFmt string
level slog.Level
}
type option func(*configuration)
var Options options
type options struct{}
func (options) Source(s source) option { return func(c *configuration) { c.source = s } }
func (options) StampFmt(s string) option { return func(c *configuration) { c.stampFmt = s } }
func (options) Level(l slog.Level) option { return func(c *configuration) { c.level = l } }
func HandlerOptions(options ...option) slog.HandlerOptions {
var config configuration
for _, option := range options {
option(&config)
}
return slog.HandlerOptions{
Level: config.level,
AddSource: config.source != SourceNone,
ReplaceAttr: func(a slog.Attr) slog.Attr {
switch a.Key {
case "source":
if config.source == SourceFile {
fields := strings.Split(a.Value.String(), ":")
path := filepath.Base(fields[0])
return slog.String("source", path+":"+fields[1])
}
case "time":
if len(config.stampFmt) > 0 {
return slog.String("time", a.Value.Time().Format(config.stampFmt))
}
}
return a
},
}
}
// SetScriptingLogger sets the default logger using an abbreviated timestamp and only basename of the source file.
// It also receives 0 or more io.Writers at which to emit logs (os.Stderr is hard-coded). I find these settings to
// work nicely in short-lived processes and scripts.
func SetScriptingLogger(outs ...io.Writer) {
options := HandlerOptions(
Options.StampFmt(time.TimeOnly),
Options.Source(SourceFile),
)
out := io.MultiWriter(append(outs, os.Stderr)...)
slog.SetDefault(slog.New(options.NewTextHandler(out)))
}
package slogging_test
import (
"os"
"time"
"golang.org/x/exp/slog"
"slogging"
)
func ExampleHandlerOptions() {
options := slogging.HandlerOptions(
slogging.Options.Level(slog.WarnLevel),
slogging.Options.Source(slogging.SourceFile),
slogging.Options.StampFmt(time.TimeOnly),
)
slog.SetDefault(slog.New(options.NewTextHandler(os.Stderr)))
slog.Warn("hello", slog.String("recipient", "world"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment