This adds a package-level variable, slog.DiscardHandler, which is a
slog.Handler which performs no output. This serves a similar purpose
to io.Discard.
Fixes #62005
Change-Id: Ia8babc55f860dec9b663a5c400090a7669608fd5
GitHub-Last-Rev:
0a611174ee8819a2f4e1b8e196a60d5acc6ef9f7
GitHub-Pull-Request: golang/go#70296
Reviewed-on: https://go-review.googlesource.com/c/go/+/626486
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
--- /dev/null
+pkg log/slog, var DiscardHandler Handler #62005
--- /dev/null
+The new [DiscardHandler] is a handler that is never enabled and always discards its output.
--- /dev/null
+package slog_test
+
+import (
+ "log/slog"
+ "log/slog/internal/slogtest"
+ "os"
+)
+
+func ExampleDiscardHandler() {
+ // A slog.TextHandler can output log messages.
+ logger1 := slog.New(slog.NewTextHandler(
+ os.Stdout,
+ &slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime},
+ ))
+ logger1.Info("message 1")
+
+ // A slog.DiscardHandler will discard all messages.
+ logger2 := slog.New(slog.DiscardHandler)
+ logger2.Info("message 2")
+
+ // Output:
+ // level=INFO msg="message 1"
+}
b = append(b[:n+prefixLen], b[n+prefixLen+1:]...) // drop the 4th digit
return b
}
+
+// DiscardHandler discards all log output.
+// DiscardHandler.Enabled returns false for all Levels.
+var DiscardHandler Handler = discardHandler{}
+
+type discardHandler struct{}
+
+func (dh discardHandler) Enabled(context.Context, Level) bool { return false }
+func (dh discardHandler) Handle(context.Context, Record) error { return nil }
+func (dh discardHandler) WithAttrs(attrs []Attr) Handler { return dh }
+func (dh discardHandler) WithGroup(name string) Handler { return dh }
"context"
"encoding/json"
"io"
+ "os"
"path/filepath"
"slices"
"strconv"
buf = appendRFC3339Millis(buf[:0], tm)
}
}
+
+func TestDiscardHandler(t *testing.T) {
+ ctx := context.Background()
+ stdout, stderr := os.Stdout, os.Stderr
+ os.Stdout, os.Stderr = nil, nil // panic on write
+ t.Cleanup(func() {
+ os.Stdout, os.Stderr = stdout, stderr
+ })
+
+ // Just ensure nothing panics during normal usage
+ l := New(DiscardHandler)
+ l.Info("msg", "a", 1, "b", 2)
+ l.Debug("bg", Int("a", 1), "b", 2)
+ l.Warn("w", Duration("dur", 3*time.Second))
+ l.Error("bad", "a", 1)
+ l.Log(ctx, LevelWarn+1, "w", Int("a", 1), String("b", "two"))
+ l.LogAttrs(ctx, LevelInfo+1, "a b c", Int("a", 1), String("b", "two"))
+ l.Info("info", "a", []Attr{Int("i", 1)})
+ l.Info("info", "a", GroupValue(Int("i", 1)))
+}
func TestAlloc(t *testing.T) {
ctx := context.Background()
- dl := New(discardHandler{})
+ dl := New(discardTestHandler{})
defer SetDefault(Default()) // restore
SetDefault(dl)
})
})
t.Run("2 pairs disabled inline", func(t *testing.T) {
- l := New(discardHandler{disabled: true})
+ l := New(DiscardHandler)
s := "abc"
i := 2000
wantAllocs(t, 2, func() {
})
})
t.Run("2 pairs disabled", func(t *testing.T) {
- l := New(discardHandler{disabled: true})
+ l := New(DiscardHandler)
s := "abc"
i := 2000
wantAllocs(t, 0, func() {
})
})
t.Run("attrs3 disabled", func(t *testing.T) {
- logger := New(discardHandler{disabled: true})
+ logger := New(DiscardHandler)
wantAllocs(t, 0, func() {
logger.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second))
})
c.r = Record{}
}
-type discardHandler struct {
- disabled bool
- attrs []Attr
+type discardTestHandler struct {
+ attrs []Attr
}
-func (d discardHandler) Enabled(context.Context, Level) bool { return !d.disabled }
-func (discardHandler) Handle(context.Context, Record) error { return nil }
-func (d discardHandler) WithAttrs(as []Attr) Handler {
+func (d discardTestHandler) Enabled(context.Context, Level) bool { return true }
+func (discardTestHandler) Handle(context.Context, Record) error { return nil }
+func (d discardTestHandler) WithAttrs(as []Attr) Handler {
d.attrs = concat(d.attrs, as)
return d
}
-func (h discardHandler) WithGroup(name string) Handler {
+func (h discardTestHandler) WithGroup(name string) Handler {
return h
}