mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
log/slog: add DiscardHandler
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>
This commit is contained in:
parent
cd35323be9
commit
3d61de41a2
1
api/next/62005.txt
Normal file
1
api/next/62005.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
pkg log/slog, var DiscardHandler Handler #62005
|
1
doc/next/6-stdlib/99-minor/log/slog/62005.md
Normal file
1
doc/next/6-stdlib/99-minor/log/slog/62005.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
The new [DiscardHandler] is a handler that is never enabled and always discards its output.
|
23
src/log/slog/example_discard_test.go
Normal file
23
src/log/slog/example_discard_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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"
|
||||||
|
}
|
@ -602,3 +602,14 @@ func appendRFC3339Millis(b []byte, t time.Time) []byte {
|
|||||||
b = append(b[:n+prefixLen], b[n+prefixLen+1:]...) // drop the 4th digit
|
b = append(b[:n+prefixLen], b[n+prefixLen+1:]...) // drop the 4th digit
|
||||||
return b
|
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 }
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -711,3 +712,23 @@ func BenchmarkWriteTime(b *testing.B) {
|
|||||||
buf = appendRFC3339Millis(buf[:0], tm)
|
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)))
|
||||||
|
}
|
||||||
|
@ -231,7 +231,7 @@ func TestCallDepth(t *testing.T) {
|
|||||||
|
|
||||||
func TestAlloc(t *testing.T) {
|
func TestAlloc(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
dl := New(discardHandler{})
|
dl := New(discardTestHandler{})
|
||||||
defer SetDefault(Default()) // restore
|
defer SetDefault(Default()) // restore
|
||||||
SetDefault(dl)
|
SetDefault(dl)
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ func TestAlloc(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
t.Run("2 pairs disabled inline", func(t *testing.T) {
|
t.Run("2 pairs disabled inline", func(t *testing.T) {
|
||||||
l := New(discardHandler{disabled: true})
|
l := New(DiscardHandler)
|
||||||
s := "abc"
|
s := "abc"
|
||||||
i := 2000
|
i := 2000
|
||||||
wantAllocs(t, 2, func() {
|
wantAllocs(t, 2, func() {
|
||||||
@ -269,7 +269,7 @@ func TestAlloc(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
t.Run("2 pairs disabled", func(t *testing.T) {
|
t.Run("2 pairs disabled", func(t *testing.T) {
|
||||||
l := New(discardHandler{disabled: true})
|
l := New(DiscardHandler)
|
||||||
s := "abc"
|
s := "abc"
|
||||||
i := 2000
|
i := 2000
|
||||||
wantAllocs(t, 0, func() {
|
wantAllocs(t, 0, func() {
|
||||||
@ -305,7 +305,7 @@ func TestAlloc(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
t.Run("attrs3 disabled", func(t *testing.T) {
|
t.Run("attrs3 disabled", func(t *testing.T) {
|
||||||
logger := New(discardHandler{disabled: true})
|
logger := New(DiscardHandler)
|
||||||
wantAllocs(t, 0, func() {
|
wantAllocs(t, 0, func() {
|
||||||
logger.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second))
|
logger.LogAttrs(ctx, LevelInfo, "hello", Int("a", 1), String("b", "two"), Duration("c", time.Second))
|
||||||
})
|
})
|
||||||
@ -568,18 +568,17 @@ func (c *captureHandler) clear() {
|
|||||||
c.r = Record{}
|
c.r = Record{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type discardHandler struct {
|
type discardTestHandler struct {
|
||||||
disabled bool
|
attrs []Attr
|
||||||
attrs []Attr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d discardHandler) Enabled(context.Context, Level) bool { return !d.disabled }
|
func (d discardTestHandler) Enabled(context.Context, Level) bool { return true }
|
||||||
func (discardHandler) Handle(context.Context, Record) error { return nil }
|
func (discardTestHandler) Handle(context.Context, Record) error { return nil }
|
||||||
func (d discardHandler) WithAttrs(as []Attr) Handler {
|
func (d discardTestHandler) WithAttrs(as []Attr) Handler {
|
||||||
d.attrs = concat(d.attrs, as)
|
d.attrs = concat(d.attrs, as)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
func (h discardHandler) WithGroup(name string) Handler {
|
func (h discardTestHandler) WithGroup(name string) Handler {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user