Codebase list golang-github-go-logr-logr / 945d619
funcr: Handle panic in Stringer, Marshaler, error Produce a maybe-useful error rather than panic when we are in the middle of logging a value (similar to fmt.Printf). Tim Hockin 2 years ago
2 changed file(s) with 100 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
350350 if v, ok := value.(logr.Marshaler); ok {
351351 // Replace the value with what the type wants to get logged.
352352 // That then gets handled below via reflection.
353 value = v.MarshalLog()
353 value = invokeMarshaler(v)
354354 }
355355
356356 // Handle types that want to format themselves.
357357 switch v := value.(type) {
358358 case fmt.Stringer:
359 value = v.String()
359 value = invokeStringer(v)
360360 case error:
361 value = v.Error()
361 value = invokeError(v)
362362 }
363363
364364 // Handling the most common types without reflect is a small perf win.
596596 return false
597597 }
598598
599 func invokeMarshaler(m logr.Marshaler) (ret interface{}) {
600 defer func() {
601 if r := recover(); r != nil {
602 ret = fmt.Sprintf("<panic: %s>", r)
603 }
604 }()
605 return m.MarshalLog()
606 }
607
608 func invokeStringer(s fmt.Stringer) (ret string) {
609 defer func() {
610 if r := recover(); r != nil {
611 ret = fmt.Sprintf("<panic: %s>", r)
612 }
613 }()
614 return s.String()
615 }
616
617 func invokeError(e error) (ret string) {
618 defer func() {
619 if r := recover(); r != nil {
620 ret = fmt.Sprintf("<panic: %s>", r)
621 }
622 }()
623 return e.Error()
624 }
625
599626 // Caller represents the original call site for a log line, after considering
600627 // logr.Logger.WithCallDepth and logr.Logger.WithCallStackHelper. The File and
601628 // Line fields will always be provided, while the Func field is optional.
5151 }
5252
5353 // Logging this should result in the MarshalLog() value.
54 type Tmarshaler string
54 type Tmarshaler struct{ val string }
5555
5656 func (t Tmarshaler) MarshalLog() interface{} {
5757 return struct{ Inner string }{"I am a logr.Marshaler"}
6565 return "Error(): you should not see this"
6666 }
6767
68 // Logging this should result in a panic.
69 type Tmarshalerpanic struct{ val string }
70
71 func (t Tmarshalerpanic) MarshalLog() interface{} {
72 panic("Tmarshalerpanic")
73 }
74
6875 // Logging this should result in the String() value.
69 type Tstringer string
76 type Tstringer struct{ val string }
7077
7178 func (t Tstringer) String() string {
7279 return "I am a fmt.Stringer"
7481
7582 func (t Tstringer) Error() string {
7683 return "Error(): you should not see this"
84 }
85
86 // Logging this should result in a panic.
87 type Tstringerpanic struct{ val string }
88
89 func (t Tstringerpanic) String() string {
90 panic("Tstringerpanic")
91 }
92
93 // Logging this should result in the Error() value.
94 type Terror struct{ val string }
95
96 func (t Terror) Error() string {
97 return "I am an error"
98 }
99
100 // Logging this should result in a panic.
101 type Terrorpanic struct{ val string }
102
103 func (t Terrorpanic) Error() string {
104 panic("Terrorpanic")
77105 }
78106
79107 type TjsontagsString struct {
350378 },
351379 },
352380 {
353 val: Tmarshaler("foobar"),
381 val: Tmarshaler{"foobar"},
354382 exp: `{"Inner":"I am a logr.Marshaler"}`,
355383 },
356384 {
357 val: Tstringer("foobar"),
385 val: &Tmarshaler{"foobar"},
386 exp: `{"Inner":"I am a logr.Marshaler"}`,
387 },
388 {
389 val: (*Tmarshaler)(nil),
390 exp: `"<panic: value method github.com/go-logr/logr/funcr.Tmarshaler.MarshalLog called using nil *Tmarshaler pointer>"`,
391 },
392 {
393 val: Tmarshalerpanic{"foobar"},
394 exp: `"<panic: Tmarshalerpanic>"`,
395 },
396 {
397 val: Tstringer{"foobar"},
358398 exp: `"I am a fmt.Stringer"`,
359399 },
360400 {
361 val: fmt.Errorf("error"),
362 exp: `"error"`,
401 val: &Tstringer{"foobar"},
402 exp: `"I am a fmt.Stringer"`,
403 },
404 {
405 val: (*Tstringer)(nil),
406 exp: `"<panic: value method github.com/go-logr/logr/funcr.Tstringer.String called using nil *Tstringer pointer>"`,
407 },
408 {
409 val: Tstringerpanic{"foobar"},
410 exp: `"<panic: Tstringerpanic>"`,
411 },
412 {
413 val: Terror{"foobar"},
414 exp: `"I am an error"`,
415 },
416 {
417 val: &Terror{"foobar"},
418 exp: `"I am an error"`,
419 },
420 {
421 val: (*Terror)(nil),
422 exp: `"<panic: value method github.com/go-logr/logr/funcr.Terror.Error called using nil *Terror pointer>"`,
423 },
424 {
425 val: Terrorpanic{"foobar"},
426 exp: `"<panic: Terrorpanic>"`,
363427 },
364428 {
365429 val: TjsontagsString{