diff --git a/zapcore/field.go b/zapcore/field.go index 6a5e33e2f..e8fc3cd4e 100644 --- a/zapcore/field.go +++ b/zapcore/field.go @@ -109,9 +109,17 @@ func (f Field) AddTo(enc ObjectEncoder) { switch f.Type { case ArrayMarshalerType: - err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler)) + if am, ok := f.Interface.(ArrayMarshaler); ok && am != nil && !isNil(am) { + err = enc.AddArray(f.Key, am) + } else { + enc.AddString(f.Key, "nil") + } case ObjectMarshalerType: - err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler)) + if om, ok := f.Interface.(ObjectMarshaler); ok && om != nil && !isNil(om) { + err = enc.AddObject(f.Key, om) + } else { + enc.AddString(f.Key, "nil") + } case BinaryType: enc.AddBinary(f.Key, f.Interface.([]byte)) case BoolType: @@ -160,7 +168,11 @@ func (f Field) AddTo(enc ObjectEncoder) { case NamespaceType: enc.OpenNamespace(f.Key) case StringerType: - enc.AddString(f.Key, f.Interface.(fmt.Stringer).String()) + if s, ok := f.Interface.(fmt.Stringer); ok && s != nil && !isNil(s) { + enc.AddString(f.Key, s.String()) + } else { + enc.AddString(f.Key, "nil") + } case ErrorType: encodeError(f.Key, f.Interface.(error), enc) case SkipType: @@ -199,3 +211,7 @@ func addFields(enc ObjectEncoder, fields []Field) { fields[i].AddTo(enc) } } + +func isNil(ti interface{}) bool { + return reflect.ValueOf(ti) == reflect.Zero(reflect.TypeOf(ti)) +} \ No newline at end of file diff --git a/zapcore/field_test.go b/zapcore/field_test.go index 9a5fe0189..a035da5d3 100644 --- a/zapcore/field_test.go +++ b/zapcore/field_test.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "math" + "net/url" "testing" "time" @@ -229,3 +230,20 @@ func TestEquals(t *testing.T) { assert.Equal(t, tt.want, tt.b.Equals(tt.a), "b.Equals(a) a: %#v b: %#v", tt.a, tt.b) } } + +func TestFieldNilValue(t *testing.T) { + tests := []struct { + t FieldType + iface interface{} + }{ + {StringerType, (*url.URL)(nil)}, + {ArrayMarshalerType, (ArrayMarshaler)(nil)}, + {ObjectMarshalerType, (ObjectMarshaler)(nil)}, + } + + for _, tt := range tests { + f := Field{Key: "k", Interface: tt.iface, Type: tt.t} + enc := NewMapObjectEncoder() + assert.NotPanics(t, func() { f.AddTo(enc) }, "Unexpected panic when adding fields with nil value.") + } +} \ No newline at end of file