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:
parent
cedc4c3467
commit
fa6bbc4954
4 changed files with 78 additions and 5 deletions
0
go.sum
Normal file
0
go.sum
Normal 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.
|
||||
|
|
|
|||
24
logger.go
24
logger.go
|
|
@ -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...)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue