-
Notifications
You must be signed in to change notification settings - Fork 0
/
accum.go
67 lines (58 loc) · 1.54 KB
/
accum.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package slogx
import (
"context"
"log/slog"
)
type payload struct {
group string
attrs []slog.Attr
parent *payload
}
type accumulator struct {
slog.Handler
last *payload
}
// Accumulator is a wrapper for slog.Handler that accumulates
// attributes and groups and passes them to the underlying handler
// only on Handle call, instead of logging them immediately.
func Accumulator(h slog.Handler) slog.Handler {
return &accumulator{Handler: h}
}
// Handle accumulates attributes and groups and then calls the wrapped handler.
func (a *accumulator) Handle(ctx context.Context, rec slog.Record) error {
if a.last != nil {
rec.AddAttrs(a.assemble()...)
}
return a.Handler.Handle(ctx, rec)
}
// WithAttrs returns a new accumulator with the given attributes.
func (a *accumulator) WithAttrs(attrs []slog.Attr) slog.Handler {
acc := *a // shallow copy
if acc.last == nil {
acc.last = &payload{}
}
acc.last.attrs = append(acc.last.attrs, attrs...)
return &acc
}
// WithGroup returns a new accumulator with the given group.
func (a *accumulator) WithGroup(group string) slog.Handler {
acc := *a // shallow copy
acc.last = &payload{group: group, parent: acc.last}
return &acc
}
func (a *accumulator) assemble() (attrs []slog.Attr) {
for p := a.last; p != nil; p = p.parent {
attrs = append(p.attrs, attrs...)
if p.group != "" {
attrs = []slog.Attr{slog.Group(p.group, listAny(attrs)...)}
}
}
return attrs
}
func listAny(attrs []slog.Attr) []any {
list := make([]any, len(attrs))
for i, a := range attrs {
list[i] = a
}
return list
}