From 981f1ded59da2f31a7da7a9903bcbdfac2cd11c4 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Wed, 10 Jun 2020 11:21:52 -0700 Subject: [PATCH] json: Don't panic for nil Encode{Time, Duration} (#835) Fixes #834 The JSON encoder assumes that encoders for `time.Time` and `time.Duration` are always specified, which causes nil pointer dereference panics. Fix this by treating nil encoders for time and duration as no-ops. This will fall back to existing logic in the JSON encoder that handles no-op time and duration encoders. --- zapcore/json_encoder.go | 8 ++++++-- zapcore/json_encoder_test.go | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/zapcore/json_encoder.go b/zapcore/json_encoder.go index 7facc1b36..9ede4a9ec 100644 --- a/zapcore/json_encoder.go +++ b/zapcore/json_encoder.go @@ -236,7 +236,9 @@ func (enc *jsonEncoder) AppendComplex128(val complex128) { func (enc *jsonEncoder) AppendDuration(val time.Duration) { cur := enc.buf.Len() - enc.EncodeDuration(val, enc) + if e := enc.EncodeDuration; e != nil { + e(val, enc) + } if cur == enc.buf.Len() { // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep // JSON valid. @@ -275,7 +277,9 @@ func (enc *jsonEncoder) AppendTimeLayout(time time.Time, layout string) { func (enc *jsonEncoder) AppendTime(val time.Time) { cur := enc.buf.Len() - enc.EncodeTime(val, enc) + if e := enc.EncodeTime; e != nil { + e(val, enc) + } if cur == enc.buf.Len() { // User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep // output JSON valid. diff --git a/zapcore/json_encoder_test.go b/zapcore/json_encoder_test.go index 82496581b..5ae34d7f7 100644 --- a/zapcore/json_encoder_test.go +++ b/zapcore/json_encoder_test.go @@ -129,3 +129,40 @@ func TestJSONEncodeEntry(t *testing.T) { }) } } + +func TestJSONEmptyConfig(t *testing.T) { + tests := []struct { + name string + field zapcore.Field + expected string + }{ + { + name: "time", + field: zap.Time("foo", time.Unix(1591287718, 0)), // 2020-06-04 09:21:58 -0700 PDT + expected: `{"foo": 1591287718000000000}`, + }, + { + name: "duration", + field: zap.Duration("bar", time.Microsecond), + expected: `{"bar": 1000}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{}) + + buf, err := enc.EncodeEntry(zapcore.Entry{ + Level: zapcore.DebugLevel, + Time: time.Now(), + LoggerName: "mylogger", + Message: "things happened", + }, []zapcore.Field{tt.field}) + if assert.NoError(t, err, "Unexpected JSON encoding error.") { + assert.JSONEq(t, tt.expected, buf.String(), "Incorrect encoded JSON entry.") + } + + buf.Free() + }) + } +}