slog: document LogValuer
Mention in the package doc, and add examples.
Change-Id: If83f4f6adb0a999aabe10bd779069cdc2ba12bdb
Reviewed-on: https://go-review.googlesource.com/c/exp/+/458205
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/slog/doc.go b/slog/doc.go
index 232bfff..20a500d 100644
--- a/slog/doc.go
+++ b/slog/doc.go
@@ -222,10 +222,17 @@
# Advanced topics
-
## Customizing a type's logging behavior
-TODO: discuss LogValuer
+If a type implements the [LogValuer] interface, the [Value] returned from its LogValue
+method is used for logging. You can use this to control how values of the type
+appear in logs. For example, you can redact secret information like passwords,
+or gather a struct's fields in a Group. See the examples under [LogValuer] for
+details.
+
+A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve]
+method handles these cases carefully, avoiding infinite loops and unbounded recursion.
+Handler authors and others may wish to use Value.Resolve instead of calling LogValue directly.
## Wrapping output methods
diff --git a/slog/example_logvaluer_test.go b/slog/example_logvaluer_group_test.go
similarity index 78%
rename from slog/example_logvaluer_test.go
rename to slog/example_logvaluer_group_test.go
index f793e4e..85426d0 100644
--- a/slog/example_logvaluer_test.go
+++ b/slog/example_logvaluer_group_test.go
@@ -12,13 +12,16 @@
First, Last string
}
+// LogValue implements slog.LogValuer.
+// It returns a group containing the fields of
+// the Name, so that they appear together in the log output.
func (n Name) LogValue() slog.Value {
return slog.GroupValue(
slog.String("first", n.First),
slog.String("last", n.Last))
}
-func ExampleLogValuer() {
+func ExampleLogValuer_group() {
n := Name{"Perry", "Platypus"}
slog.Info("mission accomplished", "agent", n)
diff --git a/slog/example_logvaluer_secret_test.go b/slog/example_logvaluer_secret_test.go
new file mode 100644
index 0000000..aa6c704
--- /dev/null
+++ b/slog/example_logvaluer_secret_test.go
@@ -0,0 +1,38 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog_test
+
+import (
+ "os"
+
+ "golang.org/x/exp/slog"
+)
+
+// A token is a secret value that grants permissions.
+type Token string
+
+// LogValue implements slog.LogValuer.
+// It avoids revealing the token.
+func (Token) LogValue() slog.Value {
+ return slog.StringValue("REDACTED_TOKEN")
+}
+
+// This example demonstrates a Value that replaces itself
+// with an alternative representation to avoid revealing secrets.
+func ExampleLogValuer_secret() {
+ t := Token("shhhh!")
+ // Remove the time attribute to make Output deterministic.
+ removeTime := func(groups []string, a slog.Attr) slog.Attr {
+ if a.Key == slog.TimeKey && len(groups) == 0 {
+ a.Key = ""
+ }
+ return a
+ }
+ logger := slog.New(slog.HandlerOptions{ReplaceAttr: removeTime}.NewTextHandler(os.Stdout))
+ logger.Info("permission granted", "user", "Perry", "token", t)
+
+ // Output:
+ // level=INFO msg="permission granted" user=Perry token=REDACTED_TOKEN
+}