1
0
Fork 0
mirror of https://github.com/chainguard-dev/clog synced 2026-07-06 22:12:46 +00:00

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.
This commit is contained in:
Billy Lynch 2025-03-03 18:20:42 -05:00 committed by GitHub
parent cedc4c3467
commit fa6bbc4954
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 78 additions and 5 deletions

0
go.sum Normal file
View file

View file

@ -6,9 +6,10 @@ import (
)
var (
ctxKey = struct{}{}
ctxKey = key{}
)
type key struct{}
type ctxVal map[string]any
// With returns a new context with the given values.

View file

@ -30,10 +30,6 @@ func NewLoggerWithContext(ctx context.Context, l *slog.Logger) *Logger {
if l == nil {
l = slog.New(NewHandler(slog.Default().Handler()))
}
// Attach any existing context values onto the logger.
for k, v := range get(ctx) {
l = l.With(k, v)
}
return &Logger{
ctx: ctx,
Logger: *l,
@ -72,6 +68,11 @@ func (l *Logger) context() context.Context {
return l.ctx
}
// Infof logs at LevelInfo with the given format and arguments.
func (l *Logger) Info(format string, args ...any) {
wrap(l.context(), l, slog.LevelInfo, format, args...)
}
// Infof logs at LevelInfo with the given format and arguments.
func (l *Logger) Infof(format string, args ...any) {
wrapf(l.context(), l, slog.LevelInfo, format, args...)
@ -82,6 +83,11 @@ func (l *Logger) InfoContextf(ctx context.Context, format string, args ...any) {
wrapf(ctx, l, slog.LevelInfo, format, args...)
}
// Warn logs at LevelWarn with the given format and arguments.
func (l *Logger) Warn(format string, args ...any) {
wrap(l.context(), l, slog.LevelWarn, format, args...)
}
// Warnf logs at LevelWarn with the given format and arguments.
func (l *Logger) Warnf(format string, args ...any) {
wrapf(l.context(), l, slog.LevelWarn, format, args...)
@ -92,6 +98,11 @@ func (l *Logger) WarnContextf(ctx context.Context, format string, args ...any) {
wrapf(ctx, l, slog.LevelWarn, format, args...)
}
// Error logs at LevelError with the given format and arguments.
func (l *Logger) Error(format string, args ...any) {
wrap(l.context(), l, slog.LevelError, format, args...)
}
// Errorf logs at LevelError with the given format and arguments.
func (l *Logger) Errorf(format string, args ...any) {
wrapf(l.context(), l, slog.LevelError, format, args...)
@ -102,6 +113,11 @@ func (l *Logger) ErrorContextf(ctx context.Context, format string, args ...any)
wrapf(ctx, l, slog.LevelError, format, args...)
}
// Debug logs at LevelDebug with the given format and arguments.
func (l *Logger) Debug(format string, args ...any) {
wrap(l.context(), l, slog.LevelDebug, format, args...)
}
// Debugf logs at LevelDebug with the given format and arguments.
func (l *Logger) Debugf(format string, args ...any) {
wrapf(l.context(), l, slog.LevelDebug, format, args...)

View file

@ -187,3 +187,59 @@ func TestDefaultHandler(t *testing.T) {
}
})
}
func TestContext(t *testing.T) {
old := slog.Default()
t.Cleanup(func() {
slog.SetDefault(old)
})
b := new(bytes.Buffer)
slog.SetDefault(slog.New(slog.NewJSONHandler(b, testopts)))
msg := "hello world"
want := map[string]any{
"level": "INFO",
"msg": msg,
"a": "b",
}
ctx := WithValues(context.Background(), "a", "b")
// These should all give the same output and be functionally equivalent.
for _, tc := range []struct {
name string
fn func()
}{
{
name: "clog.InfoContext",
fn: func() {
InfoContext(ctx, msg)
},
},
{
name: "clog.FromContext.Info",
fn: func() {
FromContext(ctx).Info(msg)
},
},
{
name: "clog.FromContext.InfoContext",
fn: func() {
FromContext(ctx).InfoContext(ctx, msg)
},
},
} {
t.Run(tc.name, func(t *testing.T) {
b.Reset()
tc.fn()
var got map[string]any
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, got) {
t.Errorf("want %v, got %v", want, got)
}
})
}
}