log/slog: function argument to Record.Attrs returns bool

Record.Attrs stops as soon as its argument function returns false.

Fixes #59060.

Change-Id: I578d64635e0e52b0fcdbc57f6d5a27a6efac8c70
Reviewed-on: https://go-review.googlesource.com/c/go/+/484096
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
Jonathan Amsterdam 2023-04-12 09:11:59 -04:00
parent d528f72d4c
commit f3e6f0f296
6 changed files with 28 additions and 8 deletions

2
api/next/59060.txt Normal file
View file

@ -0,0 +1,2 @@
pkg log/slog, method (Record) Attrs(func(Attr) bool) #59060

View file

@ -330,8 +330,9 @@ func (s *handleState) appendNonBuiltIns(r Record) {
defer s.prefix.Free()
s.prefix.WriteString(s.h.groupPrefix)
s.openGroups()
r.Attrs(func(a Attr) {
r.Attrs(func(a Attr) bool {
s.appendAttr(a)
return true
})
if s.h.json {
// Close all open groups.

View file

@ -47,11 +47,12 @@ func (h *fastTextHandler) Handle(_ context.Context, r slog.Record) error {
buf.WriteByte(' ')
buf.WriteString("msg=")
buf.WriteString(r.Message)
r.Attrs(func(a slog.Attr) {
r.Attrs(func(a slog.Attr) bool {
buf.WriteByte(' ')
buf.WriteString(a.Key)
buf.WriteByte('=')
h.appendValue(buf, a.Value)
return true
})
buf.WriteByte('\n')
_, err := h.w.Write(*buf)

View file

@ -37,6 +37,6 @@ func TestHandlers(t *testing.T) {
func attrSlice(r slog.Record) []slog.Attr {
var as []slog.Attr
r.Attrs(func(a slog.Attr) { as = append(as, a) })
r.Attrs(func(a slog.Attr) bool { as = append(as, a); return true })
return as
}

View file

@ -86,13 +86,18 @@ func (r Record) NumAttrs() int {
}
// Attrs calls f on each Attr in the Record.
// Iteration stops if f returns false.
// The Attrs are already resolved.
func (r Record) Attrs(f func(Attr)) {
func (r Record) Attrs(f func(Attr) bool) {
for i := 0; i < r.nFront; i++ {
f(r.front[i])
if !f(r.front[i]) {
return
}
}
for _, a := range r.back {
f(a)
if !f(a) {
return
}
}
}

View file

@ -23,6 +23,17 @@ func TestRecordAttrs(t *testing.T) {
if got := attrsSlice(r); !attrsEqual(got, as) {
t.Errorf("got %v, want %v", got, as)
}
// Early return.
var got []Attr
r.Attrs(func(a Attr) bool {
got = append(got, a)
return len(got) < 2
})
want := as[:2]
if !attrsEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}
func TestRecordSourceLine(t *testing.T) {
@ -102,7 +113,7 @@ func newRecordWithAttrs(as []Attr) Record {
func attrsSlice(r Record) []Attr {
s := make([]Attr, 0, r.NumAttrs())
r.Attrs(func(a Attr) { s = append(s, a) })
r.Attrs(func(a Attr) bool { s = append(s, a); return true })
return s
}
@ -157,7 +168,7 @@ func BenchmarkRecord(b *testing.B) {
for j := 0; j < nAttrs; j++ {
r.AddAttrs(Int("k", j))
}
r.Attrs(func(b Attr) { a = b })
r.Attrs(func(b Attr) bool { a = b; return true })
}
_ = a
}