slog: clip byte slice in commonHandler.clone
The clone method was failing to clip the preformattedAttrs field, a
[]byte, so the clone could affect the original.
This bug was discovered by Michael Lore.
Change-Id: I80e8fd9ca7e398272cae897520a36ac3a760cef7
Reviewed-on: https://go-review.googlesource.com/c/exp/+/449696
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
diff --git a/slog/handler.go b/slog/handler.go
index bc10a6b..e5216d1 100644
--- a/slog/handler.go
+++ b/slog/handler.go
@@ -165,7 +165,7 @@
return &commonHandler{
json: h.json,
opts: h.opts,
- preformattedAttrs: h.preformattedAttrs,
+ preformattedAttrs: slices.Clip(h.preformattedAttrs),
groupPrefix: h.groupPrefix,
groups: slices.Clip(h.groups),
nOpenGroups: h.nOpenGroups,
diff --git a/slog/handler_test.go b/slog/handler_test.go
index 0223cb8..41af25a 100644
--- a/slog/handler_test.go
+++ b/slog/handler_test.go
@@ -108,18 +108,6 @@
// remove all Attrs
removeAll := func(a Attr) Attr { return Attr{} }
- // remove the given keys
- removeKeys := func(keys ...string) func(a Attr) Attr {
- return func(a Attr) Attr {
- for _, k := range keys {
- if a.Key == k {
- return Attr{}
- }
- }
- return a
- }
- }
-
attrs := []Attr{String("a", "one"), Int("b", 2), Any("", "ignore me")}
preAttrs := []Attr{Int("pre", 3), String("x", "y")}
@@ -303,6 +291,19 @@
}
}
+// removeKeys returns a function suitable for HandlerOptions.ReplaceAttr
+// that removes all Attrs with the given keys.
+func removeKeys(keys ...string) func(a Attr) Attr {
+ return func(a Attr) Attr {
+ for _, k := range keys {
+ if a.Key == k {
+ return Attr{}
+ }
+ }
+ return a
+ }
+}
+
func upperCaseKey(a Attr) Attr {
a.Key = strings.ToUpper(a.Key)
return a
@@ -371,6 +372,26 @@
}
}
+func TestSecondWith(t *testing.T) {
+ // Verify that a second call to Logger.With does not corrupt
+ // the original.
+ var buf bytes.Buffer
+ h := HandlerOptions{ReplaceAttr: removeKeys(TimeKey)}.NewTextHandler(&buf)
+ logger := New(h).With(
+ String("app", "playground"),
+ String("role", "tester"),
+ Int("data_version", 2),
+ )
+ appLogger := logger.With("type", "log") // this becomes type=met
+ _ = logger.With("type", "metric")
+ appLogger.Info("foo")
+ got := strings.TrimSpace(buf.String())
+ want := `level=INFO msg=foo app=playground role=tester data_version=2 type=log`
+ if got != want {
+ t.Errorf("\ngot %s\nwant %s", got, want)
+ }
+}
+
const rfc3339Millis = "2006-01-02T15:04:05.000Z07:00"
func TestWriteTimeRFC3339(t *testing.T) {