slog Handler Design Deep Dive
slog Handler Design Deep Dive
Overview
log/slog separates Logger (API) from Handler (serialization + output). Custom handlers power redaction, sampling, OpenTelemetry bridges, and multi-sink fanout.
Basics: fmt/log/slog, structured logging.
Diagram: Logger vs Handler
slog.Logger
│
v
Handler
├── Enabled(level)?
├── Handle(Record) ──► JSON / text / OTel
└── WithAttrs / WithGroup
Interfaces
type Handler interface {
Enabled(ctx context.Context, level slog.Level) bool
Handle(ctx context.Context, r slog.Record) error
WithAttrs(attrs []slog.Attr) Handler
WithGroup(name string) Handler
}Rules for custom handlers:
- Honor
Enabledto avoid expensive attr work WithAttrs/WithGroupreturn new handlers (immutability)- Be concurrent-safe — loggers are shared
- Do not panic on normal records
Patterns
| Pattern | Idea |
|---|---|
| Middleware handler | Wrap another handler; filter/redact |
| Sampling | Drop debug under load |
| Fanout | Write JSON + ship metrics counter |
| Context attrs | Pull request_id from ctx in Handle |
type RedactHandler struct{ slog.Handler }
func (h RedactHandler) Handle(ctx context.Context, r slog.Record) error {
r.Attrs(func(a slog.Attr) bool {
if a.Key == "password" || a.Key == "token" {
// rebuild record without secrets — production code clones carefully
}
return true
})
return h.Handler.Handle(ctx, r)
}Performance
- JSON handler cost ≈ encoding + I/O
- Avoid
fmt.Sprintfin hot attr values - Precompute constant attrs via
With
Experiment
go mod init example
go run .package main
import (
"context"
"log/slog"
"os"
)
type MinLevel struct {
slog.Handler
min slog.Level
}
func (h MinLevel) Enabled(ctx context.Context, l slog.Level) bool {
return l >= h.min && h.Handler.Enabled(ctx, l)
}
func main() {
base := slog.NewJSONHandler(os.Stdout, nil)
log := slog.New(MinLevel{Handler: base, min: slog.LevelInfo})
log.Debug("hidden")
log.Info("visible", "n", 1)
}What to notice: Debug suppressed without formatting work beyond Enabled checks on the wrapper.
Try next: Add attribute redaction for keys authorization and cookie.