Skip to content

Commit

Permalink
handle panics in MarshalLog, Error, String
Browse files Browse the repository at this point in the history
The previous fix only covered fmt.Stringer.String in klog, but not klogr.
error.Error and logr.Marshaler.MarshalLog have the same problem. The
replacement string now captures the error, which makes it consistent with
go-logr/logr#130.
  • Loading branch information
pohly committed Feb 15, 2022
1 parent a58a994 commit 5b139da
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
22 changes: 18 additions & 4 deletions internal/serialize/keyvalues.go
Expand Up @@ -126,11 +126,11 @@ func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
// (https://github.com/kubernetes/kubernetes/pull/106594#issuecomment-975526235).
switch v := v.(type) {
case fmt.Stringer:
writeStringValue(b, true, stringerToString(v))
writeStringValue(b, true, StringerToString(v))
case string:
writeStringValue(b, true, v)
case error:
writeStringValue(b, true, v.Error())
writeStringValue(b, true, ErrorToString(v))
case []byte:
// In https://github.com/kubernetes/klog/pull/237 it was decided
// to format byte slices with "%+q". The advantages of that are:
Expand All @@ -151,16 +151,30 @@ func KVListFormat(b *bytes.Buffer, keysAndValues ...interface{}) {
}
}

func stringerToString(s fmt.Stringer) (ret string) {
// StringerToString converts a Stringer to a string,
// handling panics if they occur.
func StringerToString(s fmt.Stringer) (ret string) {
defer func() {
if err := recover(); err != nil {
ret = "nil"
ret = fmt.Sprintf("<panic: %s>", err)
}
}()
ret = s.String()
return
}

// ErrorToString converts an error to a string,
// handling panics if they occur.
func ErrorToString(err error) (ret string) {
defer func() {
if err := recover(); err != nil {
ret = fmt.Sprintf("<panic: %s>", err)
}
}()
ret = err.Error()
return
}

func writeStringValue(b *bytes.Buffer, quote bool, v string) {
data := []byte(v)
index := bytes.IndexByte(data, '\n')
Expand Down
2 changes: 1 addition & 1 deletion internal/serialize/keyvalues_test.go
Expand Up @@ -137,7 +137,7 @@ No whitespace.`,
},
{
keysValues: []interface{}{"point-1", point{100, 200}, "point-2", emptyPoint},
want: " point-1=\"x=100, y=200\" point-2=\"nil\"",
want: " point-1=\"x=100, y=200\" point-2=\"<panic: value method k8s.io/klog/v2/internal/serialize_test.point.String called using nil *point pointer>\"",
},
}

Expand Down
2 changes: 1 addition & 1 deletion klogr/klogr.go
Expand Up @@ -140,7 +140,7 @@ func (l klogger) Error(err error, msg string, kvList ...interface{}) {
msgStr := flatten("msg", msg)
var loggableErr interface{}
if err != nil {
loggableErr = err.Error()
loggableErr = serialize.ErrorToString(err)
}
switch l.format {
case FormatSerialize:
Expand Down
29 changes: 29 additions & 0 deletions test/output.go
Expand Up @@ -286,6 +286,24 @@ I output.go:<LINE>] "test" firstKey=1 secondKey=3
text: "test",
err: errors.New("whoops"),
expectedOutput: `E output.go:<LINE>] "test" err="whoops"
`,
},
"Error() that panics": {
text: "error panic",
err: (*customErrorJSON)(nil),
expectedOutput: `E output.go:<LINE>] "error panic" err="<panic: runtime error: invalid memory address or nil pointer dereference>"
`,
},
"String() that panics": {
text: "stringer panic",
values: []interface{}{"stringer", (*stringer)(nil)},
expectedOutput: `I output.go:<LINE>] "stringer panic" stringer="<panic: runtime error: invalid memory address or nil pointer dereference>"
`,
},
"MarshalLog that panics": {
text: "marshaler panic",
values: []interface{}{"obj", (*klog.ObjectRef)(nil)},
expectedOutput: `I output.go:<LINE>] "marshaler panic" obj="<panic: value method k8s.io/klog/v2.ObjectRef.String called using nil *ObjectRef pointer>"
`,
},
}
Expand Down Expand Up @@ -699,3 +717,14 @@ func (e *customErrorJSON) Error() string {
func (e *customErrorJSON) MarshalJSON() ([]byte, error) {
return json.Marshal(strings.ToUpper(e.s))
}

type stringer struct {
s string
}

// String crashes when called for nil.
func (s *stringer) String() string {
return s.s
}

var _ fmt.Stringer = &stringer{}

0 comments on commit 5b139da

Please sign in to comment.