Skip to content

Commit 1f95e53

Browse files
committed
chore: add test to custom logger for Go 1.21+
1 parent 8444c58 commit 1f95e53

File tree

2 files changed

+169
-5
lines changed

2 files changed

+169
-5
lines changed

logging/custom.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ func (cl *LoggerWrapper) Errorf(ctx context.Context, format string, v ...any) {
5454
legacyLoggerWithLevel.Errorf(ctx, format, v...)
5555
return
5656
}
57-
cl.logger.ErrorContext(cl.printfToStructured(ctx, format, v...))
57+
ctx, msg, args := cl.printfToStructured(ctx, format, v...)
58+
cl.logger.ErrorContext(ctx, msg, args...)
5859
}
5960

6061
// Warn is a structured warning level logging method with context and arguments.
@@ -71,7 +72,8 @@ func (cl *LoggerWrapper) Warnf(ctx context.Context, format string, v ...any) {
7172
legacyLoggerWithLevel.Warnf(ctx, format, v...)
7273
return
7374
}
74-
cl.logger.WarnContext(cl.printfToStructured(ctx, format, v...))
75+
ctx, msg, args := cl.printfToStructured(ctx, format, v...)
76+
cl.logger.WarnContext(ctx, msg, args...)
7577
}
7678

7779
// Info is a structured info level logging method with context and arguments.
@@ -98,15 +100,17 @@ func (cl *LoggerWrapper) Infof(ctx context.Context, format string, v ...any) {
98100
return
99101
}
100102

101-
cl.logger.InfoContext(cl.printfToStructured(ctx, format, v...))
103+
ctx, msg, args := cl.printfToStructured(ctx, format, v...)
104+
cl.logger.InfoContext(ctx, msg, args...)
102105
}
103106

104107
func (cl *LoggerWrapper) Debugf(ctx context.Context, format string, v ...any) {
105108
if cl == nil || cl.logger == nil {
106109
legacyLoggerWithLevel.Debugf(ctx, format, v...)
107110
return
108111
}
109-
cl.logger.DebugContext(cl.printfToStructured(ctx, format, v...))
112+
ctx, msg, args := cl.printfToStructured(ctx, format, v...)
113+
cl.logger.DebugContext(ctx, msg, args...)
110114
}
111115

112116
func (cl *LoggerWrapper) printfToStructured(ctx context.Context, format string, v ...any) (context.Context, string, []any) {

logging/custom_go121_test.go

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,169 @@
22

33
package logging
44

5-
import "log/slog"
5+
import (
6+
"bytes"
7+
"context"
8+
"encoding/json"
9+
"log/slog"
10+
"testing"
11+
)
612

713
// validation that [slog.Logger] implements [LoggerWithLevelI]
814
var _ LoggerWithLevelI = &slog.Logger{}
915

1016
var _ *LoggerWrapper = NewLoggerWrapper(&slog.Logger{})
17+
18+
func TestLoggerWrapper_slog(t *testing.T) {
19+
20+
ctx := context.Background()
21+
22+
t.Run("Debug", func(t *testing.T) {
23+
wrapped, buf := NewTestLogger(t)
24+
wrapped.Debug(ctx, "debug message", "foo", "bar")
25+
26+
checkLog(t, buf, map[string]any{
27+
"level": "DEBUG",
28+
"msg": "debug message",
29+
"foo": "bar",
30+
})
31+
})
32+
33+
t.Run("Info", func(t *testing.T) {
34+
wrapped, buf := NewTestLogger(t)
35+
wrapped.Info(ctx, "info message", "foo", "bar")
36+
37+
checkLog(t, buf, map[string]any{
38+
"level": "INFO",
39+
"msg": "info message",
40+
"foo": "bar",
41+
})
42+
})
43+
t.Run("Warn", func(t *testing.T) {
44+
wrapped, buf := NewTestLogger(t)
45+
wrapped.Warn(ctx, "warn message", "foo", "bar")
46+
47+
checkLog(t, buf, map[string]any{
48+
"level": "WARN",
49+
"msg": "warn message",
50+
"foo": "bar",
51+
})
52+
})
53+
t.Run("Error", func(t *testing.T) {
54+
wrapped, buf := NewTestLogger(t)
55+
wrapped.Error(ctx, "error message", "foo", "bar")
56+
57+
checkLog(t, buf, map[string]any{
58+
"level": "ERROR",
59+
"msg": "error message",
60+
"foo": "bar",
61+
})
62+
})
63+
64+
t.Run("Errorf", func(t *testing.T) {
65+
wrapped, buf := NewTestLogger(t)
66+
wrapped.Errorf(ctx, "%d is the answer to %s", 42, "everything")
67+
68+
checkLog(t, buf, map[string]any{
69+
"level": "ERROR",
70+
"msg": "42 is the answer to everything",
71+
})
72+
})
73+
74+
t.Run("Infof", func(t *testing.T) {
75+
wrapped, buf := NewTestLogger(t)
76+
wrapped.Infof(ctx, "%d is the answer to %s", 42, "everything")
77+
78+
checkLog(t, buf, map[string]any{
79+
"level": "INFO",
80+
"msg": "42 is the answer to everything",
81+
})
82+
})
83+
84+
t.Run("Warnf", func(t *testing.T) {
85+
wrapped, buf := NewTestLogger(t)
86+
wrapped.Warnf(ctx, "%d is the answer to %s", 42, "everything")
87+
88+
checkLog(t, buf, map[string]any{
89+
"level": "WARN",
90+
"msg": "42 is the answer to everything",
91+
})
92+
})
93+
94+
t.Run("Debugf", func(t *testing.T) {
95+
wrapped, buf := NewTestLogger(t)
96+
wrapped.Debugf(ctx, "%d is the answer to %s", 42, "everything")
97+
98+
checkLog(t, buf, map[string]any{
99+
"level": "DEBUG",
100+
"msg": "42 is the answer to everything",
101+
})
102+
})
103+
104+
t.Run("Insufficient loglevel: default", func(t *testing.T) {
105+
var buf bytes.Buffer
106+
wrapped := NewLoggerWrapper(slog.New(slog.NewJSONHandler(&buf, nil)))
107+
wrapped.Debug(ctx, "debug message", "foo", "bar")
108+
if buf.Len() != 0 {
109+
t.Errorf("expected no log message, got %s", buf.String())
110+
}
111+
})
112+
113+
t.Run("Insufficient loglevel: error", func(t *testing.T) {
114+
var buf bytes.Buffer
115+
wrapped := NewLoggerWrapper(slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{Level: slog.LevelError})))
116+
wrapped.Debug(ctx, "debug message", "foo", "bar")
117+
wrapped.Warn(ctx, "warn message", "foo", "bar")
118+
wrapped.Info(ctx, "info message", "foo", "bar")
119+
if buf.Len() != 0 {
120+
t.Errorf("expected no log message, got %s", buf.String())
121+
}
122+
wrapped.Error(ctx, "error message", "foo", "bar")
123+
124+
checkLog(t, &buf, map[string]any{
125+
"level": "ERROR",
126+
"msg": "error message",
127+
"foo": "bar",
128+
})
129+
})
130+
}
131+
132+
func NewTestLogger(t *testing.T) (*LoggerWrapper, *bytes.Buffer) {
133+
var buf bytes.Buffer
134+
wrapped := NewLoggerWrapper(slog.New(slog.NewJSONHandler(&buf, &slog.HandlerOptions{Level: slog.LevelDebug})))
135+
return wrapped, &buf
136+
}
137+
138+
func checkLog(t *testing.T, buf *bytes.Buffer, attrs map[string]any) {
139+
t.Helper()
140+
141+
res := buf.Bytes()
142+
143+
var m map[string]any
144+
err := json.Unmarshal(res, &m)
145+
if err != nil {
146+
t.Fatalf("failed to unmarshal log message: %v", err)
147+
}
148+
149+
delete(m, "time") // remove time for testing purposes
150+
151+
if len(m) != len(attrs) {
152+
t.Errorf("expected %d attributes, got %d", len(attrs), len(m))
153+
}
154+
155+
for k, expected := range attrs {
156+
v, ok := m[k]
157+
if !ok {
158+
t.Errorf("expected log to have key %s", k)
159+
continue
160+
}
161+
if v != expected {
162+
t.Errorf("expected %s to be %v, got %v", k, expected, v)
163+
}
164+
}
165+
166+
if t.Failed() {
167+
t.Logf("log message: %s", res)
168+
t.Log("time is ignored in comparison")
169+
}
170+
}

0 commit comments

Comments
 (0)