Skip to content

Commit

Permalink
klogr: improve handling of missing value in WithValues
Browse files Browse the repository at this point in the history
This is invalid:
   logger.WithValue("keyWithoutValue").WithValue("anotherKeyWithoutValue")

Because it concatenated key/values without checking, klogr treated this like:
   logger.WithValue("keyWithoutValue", "anotherKeyWithoutValue")

Now the parameters are checked and a "(MISSING)" is appended as in the other
cases where a missing value is detected.
  • Loading branch information
pohly committed Feb 11, 2022
1 parent 301ac04 commit ffefa32
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 15 deletions.
22 changes: 22 additions & 0 deletions internal/serialize/keyvalues.go
Expand Up @@ -22,6 +22,28 @@ import (
"strconv"
)

// WithValues implements LogSink.WithValues. The old key/value pairs are
// assumed to be well-formed, the new ones are checked and padded if
// necessary. It returns a new slice.
func WithValues(oldKV, newKV []interface{}) []interface{} {
if len(newKV) == 0 {
return oldKV
}
newLen := len(oldKV) + len(newKV)
hasMissingValue := newLen%2 != 0
if hasMissingValue {
newLen++
}
// The new LogSink must have its own slice.
kv := make([]interface{}, 0, newLen)
kv = append(kv, oldKV...)
kv = append(kv, newKV...)
if hasMissingValue {
kv = append(kv, missingValue)
}
return kv
}

// TrimDuplicates deduplicates elements provided in multiple key/value tuple
// slices, whilst maintaining the distinction between where the items are
// contained.
Expand Down
4 changes: 1 addition & 3 deletions klogr/klogr.go
Expand Up @@ -170,9 +170,7 @@ func (l klogger) WithName(name string) logr.LogSink {
}

func (l klogger) WithValues(kvList ...interface{}) logr.LogSink {
// Three slice args forces a copy.
n := len(l.values)
l.values = append(l.values[:n:n], kvList...)
l.values = serialize.WithValues(l.values, kvList)
return &l
}

Expand Down
9 changes: 9 additions & 0 deletions klogr/klogr_test.go
Expand Up @@ -116,6 +116,15 @@ func testOutput(t *testing.T, format string) {
expectedOutput: ` "msg"="test" "akey"="avalue" "akey2"="(MISSING)"
`,
expectedKlogOutput: `"test" akey="avalue" akey2="(MISSING)"
`,
},
"should correctly handle odd-numbers of KVs in WithValue": {
klogr: new().WithValues("keyWithoutValue"),
text: "test",
keysAndValues: []interface{}{"akey", "avalue", "akey2"},
expectedOutput: ` "msg"="test" "keyWithoutValue"="(MISSING)" "akey"="avalue" "akey2"="(MISSING)"
`,
expectedKlogOutput: `"test" keyWithoutValue="(MISSING)" akey="avalue" akey2="(MISSING)"
`,
},
"should correctly html characters": {
Expand Down
12 changes: 0 additions & 12 deletions test/output_test.go
Expand Up @@ -36,21 +36,9 @@ func TestKlogOutput(t *testing.T) {

// TestKlogrOutput tests klogr output via klog.
func TestKlogrOutput(t *testing.T) {
// klogr currently doesn't produce exactly the same output as klog.
// TODO: fix that.
mapping := map[string]string{
`I output.go:<LINE>] "test" keyWithoutValue="(MISSING)"
I output.go:<LINE>] "test" keyWithoutValue="(MISSING)" anotherKeyWithoutValue="(MISSING)"
I output.go:<LINE>] "test" keyWithoutValue="(MISSING)"
`: `I output.go:<LINE>] "test" keyWithoutValue="(MISSING)"
I output.go:<LINE>] "test" keyWithoutValue="anotherKeyWithoutValue"
I output.go:<LINE>] "test" keyWithoutValue="(MISSING)"
`,
}
Output(t, OutputConfig{
NewLogger: func(out io.Writer, v int, vmodule string) logr.Logger {
return klogr.NewWithOptions(klogr.WithFormat(klogr.FormatKlog))
},
ExpectedOutputMapping: mapping,
})
}

0 comments on commit ffefa32

Please sign in to comment.