From 663c5906964479601729b7b0795c6469f3b99d42 Mon Sep 17 00:00:00 2001 From: Andy Schweig Date: Fri, 28 Aug 2020 10:20:35 -0700 Subject: [PATCH] Show "" for nil Stringer. (#854) In encodeStringer, instead of returning an error when a panic occurs when calling String() on a nil pointer, use the string value "" like the fmt package does. It is not always possible to handle this case by fixing the implementation of String to not panic. This requires implementing String with a pointer receiver, which doesn't work if you need to be able to call String on non-addressable values. --- zapcore/field.go | 7 ++++++- zapcore/field_test.go | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/zapcore/field.go b/zapcore/field.go index 6e05f831f..ef46656be 100644 --- a/zapcore/field.go +++ b/zapcore/field.go @@ -208,7 +208,12 @@ func addFields(enc ObjectEncoder, fields []Field) { func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (err error) { defer func() { if v := recover(); v != nil { - err = fmt.Errorf("PANIC=%v", v) + val := reflect.ValueOf(stringer) + if val.Kind() == reflect.Ptr && val.IsNil() { + enc.AddString(key, "") + } else { + err = fmt.Errorf("PANIC=%v", v) + } } }() diff --git a/zapcore/field_test.go b/zapcore/field_test.go index a0c9c12b7..44aeee62e 100644 --- a/zapcore/field_test.go +++ b/zapcore/field_test.go @@ -102,7 +102,6 @@ func TestFieldAddingError(t *testing.T) { {t: StringerType, iface: &obj{1}, want: empty, err: "PANIC=panic with string"}, {t: StringerType, iface: &obj{2}, want: empty, err: "PANIC=panic with error"}, {t: StringerType, iface: &obj{3}, want: empty, err: "PANIC="}, - {t: StringerType, iface: (*url.URL)(nil), want: empty, err: "PANIC=runtime error: invalid memory address or nil pointer dereference"}, } for _, tt := range tests { f := Field{Key: "k", Interface: tt.iface, Type: tt.t} @@ -149,6 +148,8 @@ func TestFields(t *testing.T) { {t: StringerType, iface: &obj{}, want: "obj"}, {t: StringerType, iface: (*obj)(nil), want: "nil obj"}, {t: SkipType, want: interface{}(nil)}, + {t: StringerType, iface: (*url.URL)(nil), want: ""}, + {t: StringerType, iface: (*users)(nil), want: ""}, } for _, tt := range tests {