Skip to content

Commit a58a296

Browse files
committed
funcr: Handle nil Stringer, Marshaler, error
Produce a useful error rather thn panic.
1 parent eb02c45 commit a58a296

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

funcr/funcr.go

+28-5
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,17 @@ const (
341341
flagRawStruct = 0x1 // do not print braces on structs
342342
)
343343

344+
func isNil(i interface{}) bool {
345+
if i == nil {
346+
return true
347+
}
348+
switch reflect.TypeOf(i).Kind() {
349+
case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice:
350+
return reflect.ValueOf(i).IsNil()
351+
}
352+
return false
353+
}
354+
344355
// TODO: This is not fast. Most of the overhead goes here.
345356
func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) string {
346357
if depth > f.opts.MaxLogDepth {
@@ -349,17 +360,29 @@ func (f Formatter) prettyWithFlags(value interface{}, flags uint32, depth int) s
349360

350361
// Handle types that take full control of logging.
351362
if v, ok := value.(logr.Marshaler); ok {
352-
// Replace the value with what the type wants to get logged.
353-
// That then gets handled below via reflection.
354-
value = v.MarshalLog()
363+
if isNil(v) {
364+
value = "<nil-logr-marshaler>"
365+
} else {
366+
// Replace the value with what the type wants to get logged.
367+
// That then gets handled below via reflection.
368+
value = v.MarshalLog()
369+
}
355370
}
356371

357372
// Handle types that want to format themselves.
358373
switch v := value.(type) {
359374
case fmt.Stringer:
360-
value = v.String()
375+
if isNil(v) {
376+
value = "<nil-fmt-stringer>"
377+
} else {
378+
value = v.String()
379+
}
361380
case error:
362-
value = v.Error()
381+
if isNil(v) {
382+
value = "<nil-error>"
383+
} else {
384+
value = v.Error()
385+
}
363386
}
364387

365388
// Handling the most common types without reflect is a small perf win.

funcr/funcr_test.go

+37-6
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (p pointErr) MarshalText() ([]byte, error) {
5252
}
5353

5454
// Logging this should result in the MarshalLog() value.
55-
type Tmarshaler string
55+
type Tmarshaler struct{ val string }
5656

5757
func (t Tmarshaler) MarshalLog() interface{} {
5858
return struct{ Inner string }{"I am a logr.Marshaler"}
@@ -67,7 +67,7 @@ func (t Tmarshaler) Error() string {
6767
}
6868

6969
// Logging this should result in the String() value.
70-
type Tstringer string
70+
type Tstringer struct{ val string }
7171

7272
func (t Tstringer) String() string {
7373
return "I am a fmt.Stringer"
@@ -77,6 +77,13 @@ func (t Tstringer) Error() string {
7777
return "Error(): you should not see this"
7878
}
7979

80+
// Logging this should result in the Error() value.
81+
type Terror struct{ val string }
82+
83+
func (t Terror) Error() string {
84+
return "I am an error"
85+
}
86+
8087
type TjsontagsString struct {
8188
String1 string `json:"string1"` // renamed
8289
String2 string `json:"-"` // ignored
@@ -351,16 +358,40 @@ func TestPretty(t *testing.T) {
351358
},
352359
},
353360
{
354-
val: Tmarshaler("foobar"),
361+
val: Tmarshaler{"foobar"},
355362
exp: `{"Inner":"I am a logr.Marshaler"}`,
356363
},
357364
{
358-
val: Tstringer("foobar"),
365+
val: &Tmarshaler{"foobar"},
366+
exp: `{"Inner":"I am a logr.Marshaler"}`,
367+
},
368+
{
369+
val: (*Tmarshaler)(nil),
370+
exp: `"<nil-logr-marshaler>"`,
371+
},
372+
{
373+
val: Tstringer{"foobar"},
359374
exp: `"I am a fmt.Stringer"`,
360375
},
361376
{
362-
val: fmt.Errorf("error"),
363-
exp: `"error"`,
377+
val: &Tstringer{"foobar"},
378+
exp: `"I am a fmt.Stringer"`,
379+
},
380+
{
381+
val: (*Tstringer)(nil),
382+
exp: `"<nil-fmt-stringer>"`,
383+
},
384+
{
385+
val: Terror{"foobar"},
386+
exp: `"I am an error"`,
387+
},
388+
{
389+
val: &Terror{"foobar"},
390+
exp: `"I am an error"`,
391+
},
392+
{
393+
val: (*Terror)(nil),
394+
exp: `"<nil-error>"`,
364395
},
365396
{
366397
val: TjsontagsString{

0 commit comments

Comments
 (0)