1
0
Fork 0
mirror of https://github.com/chainguard-dev/clog synced 2026-07-06 22:12:46 +00:00
clog/handler.go
Billy Lynch fa6bbc4954
Fix duplicate log keys from context. (#34)
Because we were using attr.With, we were setting the logger attributes,
and then appending the log context attributes again later for any
contextf functions. This changes the behavior to use the context for any
log.Info functions.
2025-03-03 18:20:42 -05:00

91 lines
1.9 KiB
Go

package clog
import (
"context"
"log/slog"
)
var (
ctxKey = key{}
)
type key struct{}
type ctxVal map[string]any
// With returns a new context with the given values.
// Values are expected to be key-value pairs, where the key is a string.
// e.g. WithValues(ctx, "foo", "bar", "baz", 1)
// If a value already exists, it is overwritten.
// If an odd number of arguments are provided, With panics.
func WithValues(ctx context.Context, args ...any) context.Context {
if len(args)%2 != 0 {
panic("non-even number of arguments")
}
values := ctxVal{}
// Copy existing values
for k, v := range get(ctx) {
values[k] = v
}
for i := 0; i < len(args); i++ {
key, ok := args[i].(string)
if !ok {
panic("non-string key")
}
i++
if i >= len(args) {
break
}
value := args[i]
values[key] = value
}
return context.WithValue(ctx, ctxKey, values)
}
func get(ctx context.Context) ctxVal {
if value, ok := ctx.Value(ctxKey).(ctxVal); ok {
return value
}
return nil
}
// Handler is a slog.Handler that adds context values to the log record.
// Values are added via [WithValues].
type Handler struct {
h slog.Handler
}
// NewHandler configures a new context aware slog handler.
// If h is nil, the default slog handler is used.
func NewHandler(h slog.Handler) Handler {
return Handler{h}
}
func (h Handler) inner() slog.Handler {
if h.h == nil {
return slog.Default().Handler()
}
return h.h
}
func (h Handler) Enabled(ctx context.Context, level slog.Level) bool {
return h.inner().Enabled(ctx, level)
}
func (h Handler) Handle(ctx context.Context, r slog.Record) error {
values := get(ctx)
for k, v := range values {
r.Add(k, v)
}
return h.inner().Handle(ctx, r)
}
func (h Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
return Handler{h.inner().WithAttrs(attrs)}
}
func (h Handler) WithGroup(name string) slog.Handler {
return Handler{h.inner().WithGroup(name)}
}