Skip to content

Commit 195e54d

Browse files
Update zap logger
1 parent c6a867a commit 195e54d

File tree

3 files changed

+173
-26
lines changed

3 files changed

+173
-26
lines changed

Gopkg.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extension/zap/zap.go

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,65 @@ func Wrap(logger *zap.Logger) goengine.Logger {
1414
return &wrapper{logger}
1515
}
1616

17-
// Error writes a log with log level error
18-
func (w wrapper) Error(msg string) {
19-
w.logger.Error(msg)
17+
func (w wrapper) Error(msg string, fields func(goengine.LoggerEntry)) {
18+
if ce := w.logger.Check(zap.ErrorLevel, msg); ce != nil {
19+
ce.Write(fieldsToZapFields(fields)...)
20+
}
2021
}
2122

22-
// Warn writes a log with log level warning
23-
func (w wrapper) Warn(msg string) {
24-
w.logger.Warn(msg)
23+
func (w wrapper) Warn(msg string, fields func(goengine.LoggerEntry)) {
24+
if ce := w.logger.Check(zap.WarnLevel, msg); ce != nil {
25+
ce.Write(fieldsToZapFields(fields)...)
26+
}
2527
}
2628

27-
// Info writes a log with log level info
28-
func (w wrapper) Info(msg string) {
29-
w.logger.Info(msg)
29+
func (w wrapper) Info(msg string, fields func(goengine.LoggerEntry)) {
30+
if ce := w.logger.Check(zap.InfoLevel, msg); ce != nil {
31+
ce.Write(fieldsToZapFields(fields)...)
32+
}
3033
}
3134

32-
// Debug writes a log with log level debug
33-
func (w wrapper) Debug(msg string) {
34-
w.logger.Debug(msg)
35+
func (w wrapper) Debug(msg string, fields func(goengine.LoggerEntry)) {
36+
if ce := w.logger.Check(zap.DebugLevel, msg); ce != nil {
37+
ce.Write(fieldsToZapFields(fields)...)
38+
}
3539
}
3640

37-
// WithField Adds a field to the log entry
38-
func (w wrapper) WithField(key string, val interface{}) goengine.Logger {
39-
return wrapper{logger: w.logger.With(zap.Any(key, val))}
41+
func (w *wrapper) WithFields(fields func(goengine.LoggerEntry)) goengine.Logger {
42+
if fields == nil {
43+
return w
44+
}
45+
46+
return &wrapper{logger: w.logger.With(fieldsToZapFields(fields)...)}
4047
}
4148

42-
//WithFields Adds a set of fields to the log entry
43-
func (w wrapper) WithFields(fields goengine.Fields) goengine.Logger {
44-
zapFields := make([]zap.Field, 0, len(fields))
45-
for k, v := range fields {
46-
zapFields = append(zapFields, zap.Any(k, v))
49+
func fieldsToZapFields(fields func(goengine.LoggerEntry)) []zap.Field {
50+
if fields == nil {
51+
return make([]zap.Field, 0)
4752
}
4853

49-
return wrapper{logger: w.logger.With(zapFields...)}
54+
// TODO use some sort of pool
55+
e := &entry{fields: []zap.Field{}}
56+
fields(e)
57+
return e.fields
58+
}
59+
60+
type entry struct {
61+
fields []zap.Field
62+
}
63+
64+
func (e *entry) Int(k string, v int) {
65+
e.fields = append(e.fields, zap.Int(k, v))
66+
}
67+
68+
func (e *entry) String(k, v string) {
69+
e.fields = append(e.fields, zap.String(k, v))
70+
}
71+
72+
func (e *entry) Error(err error) {
73+
e.fields = append(e.fields, zap.Error(err))
5074
}
5175

52-
// WithError Add an error as single field to the log entry
53-
func (w wrapper) WithError(err error) goengine.Logger {
54-
return wrapper{logger: w.logger.With(zap.Error(err))}
76+
func (e *entry) Any(k string, v interface{}) {
77+
e.fields = append(e.fields, zap.Any(k, v))
5578
}

extension/zap/zap_test.go

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,135 @@
33
package zap_test
44

55
import (
6+
"errors"
67
"testing"
78

89
"github.com/hellofresh/goengine"
9-
1010
zapExtension "github.com/hellofresh/goengine/extension/zap"
11+
"github.com/stretchr/testify/assert"
1112
"go.uber.org/zap"
13+
"go.uber.org/zap/zapcore"
14+
"go.uber.org/zap/zaptest/observer"
1215
)
1316

17+
func TestWrap_LogEntry(t *testing.T) {
18+
zapCore, logObserver := observer.New(zapcore.DebugLevel)
19+
logger := zapExtension.Wrap(zap.New(zapCore))
20+
21+
testCases := []struct {
22+
msg string
23+
fields func(goengine.LoggerEntry)
24+
25+
expectedMsg string
26+
expectedContext map[string]interface{}
27+
}{
28+
{
29+
"test nil fields",
30+
nil,
31+
"test nil fields",
32+
map[string]interface{}{},
33+
},
34+
{
35+
"test with fields",
36+
func(e goengine.LoggerEntry) {
37+
e.String("test", "a value")
38+
e.Int("normal_int", 99)
39+
e.Int64("int_64", 2)
40+
e.Error(errors.New("some error"))
41+
e.Any("obj", struct {
42+
test string
43+
}{test: "test property"})
44+
},
45+
"test with fields",
46+
map[string]interface{}{
47+
"test": "a value",
48+
"normal_int": int64(99),
49+
"int_64": int64(2),
50+
"error": "some error",
51+
"obj": struct {
52+
test string
53+
}{test: "test property"},
54+
},
55+
},
56+
}
57+
58+
for _, testCase := range testCases {
59+
t.Run(testCase.msg, func(t *testing.T) {
60+
logger.Error(testCase.msg, testCase.fields)
61+
logger.Warn(testCase.msg, testCase.fields)
62+
logger.Info(testCase.msg, testCase.fields)
63+
logger.Debug(testCase.msg, testCase.fields)
64+
65+
logs := logObserver.TakeAll()
66+
67+
if !assert.Len(t, logs, 4) {
68+
return
69+
}
70+
71+
levelOrder := []zapcore.Level{
72+
zapcore.ErrorLevel,
73+
zapcore.WarnLevel,
74+
zapcore.InfoLevel,
75+
zapcore.DebugLevel,
76+
}
77+
78+
for i, level := range levelOrder {
79+
assert.Equal(t, level, logs[i].Level)
80+
assert.Equal(t, testCase.expectedMsg, logs[i].Message)
81+
assert.Equal(t, testCase.expectedContext, logs[i].ContextMap())
82+
}
83+
})
84+
}
85+
86+
t.Run("Do not log disabled levels", func(t *testing.T) {
87+
zapCore, logObserver := observer.New(zapcore.InfoLevel)
88+
logger := zapExtension.Wrap(zap.New(zapCore))
89+
90+
logger.Debug("should not be logged", func(e goengine.LoggerEntry) {
91+
t.Error("fields should not be called")
92+
})
93+
94+
assert.Equal(t, 0, logObserver.Len())
95+
})
96+
}
97+
98+
func TestWrapper_WithFields(t *testing.T) {
99+
zapCore, logObserver := observer.New(zapcore.DebugLevel)
100+
logger := zapExtension.Wrap(zap.New(zapCore))
101+
102+
t.Run("With fields", func(t *testing.T) {
103+
loggerWithFields := logger.WithFields(func(e goengine.LoggerEntry) {
104+
e.String("with field", "check")
105+
e.String("val", "default")
106+
})
107+
108+
loggerWithFields.Debug("test with nil", nil)
109+
loggerWithFields.Debug("test with override", func(e goengine.LoggerEntry) {
110+
e.String("val", "override")
111+
})
112+
113+
logs := logObserver.TakeAll()
114+
if assert.Len(t, logs, 2) {
115+
assert.Equal(t, "test with nil", logs[0].Message)
116+
assert.Equal(t, map[string]interface{}{
117+
"with field": "check",
118+
"val": "default",
119+
}, logs[0].ContextMap())
120+
121+
assert.Equal(t, "test with override", logs[1].Message)
122+
assert.Equal(t, map[string]interface{}{
123+
"with field": "check",
124+
"val": "override",
125+
}, logs[1].ContextMap())
126+
}
127+
})
128+
129+
t.Run("With fields nil", func(t *testing.T) {
130+
loggerWithFields := logger.WithFields(nil)
131+
assert.Equal(t, logger, loggerWithFields)
132+
})
133+
}
134+
14135
func BenchmarkStandardLoggerEntry(b *testing.B) {
15136
b.ReportAllocs()
16137

0 commit comments

Comments
 (0)