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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
package logging
import (
"encoding/json"
"fmt"
"iter"
"log/slog"
"runtime"
"slices"
"strings"
)
func RecordAll(r slog.Record, replaceAttr func(groups []string, a slog.Attr) slog.Attr) iter.Seq2[[]string, slog.Attr] {
return func(yield func([]string, slog.Attr) bool) {
var walk func([]string, slog.Attr) bool
walk = func(groups []string, a slog.Attr) bool {
if replaceAttr != nil {
a = replaceAttr(groups, a)
}
if a.Key == "" {
return true
}
a.Value = a.Value.Resolve()
if a.Value.Kind() == slog.KindGroup {
newGroups := append(slices.Clone(groups), a.Key)
for _, child := range a.Value.Group() {
if !walk(newGroups, child) {
return false
}
}
return true
}
return yield(groups, a)
}
if !r.Time.IsZero() {
if !walk([]string{}, slog.Time(slog.TimeKey, r.Time)) {
return
}
}
if !walk([]string{}, slog.Any(slog.LevelKey, r.Level)) {
return
}
if !walk([]string{}, slog.String(slog.MessageKey, r.Message)) {
return
}
if r.PC != 0 {
if !walk([]string{}, slog.Uint64(slog.SourceKey, uint64(r.PC))) {
return
}
}
r.Attrs(func(attr slog.Attr) bool {
return walk([]string{}, attr)
})
}
}
type Encoder func(iter.Seq2[[]string, slog.Attr]) (string, error)
func LogFmtEncoder(attrs iter.Seq2[[]string, slog.Attr]) (string, error) {
str := []string{}
for groups, attr := range attrs {
if len(groups) == 0 && attr.Key == slog.SourceKey {
pc := uintptr(attr.Value.Uint64())
fs := runtime.CallersFrames([]uintptr{pc})
f, _ := fs.Next()
attr.Value = slog.StringValue(fmt.Sprintf("%s:%d", f.File, f.Line))
}
str = append(str, fmt.Sprintf("%s=%q", strings.Join(append(groups, attr.Key), "."), attr.Value))
}
return strings.Join(str, " "), nil
}
func ToMap(seq iter.Seq2[[]string, slog.Attr]) map[string]any {
out := make(map[string]any)
for groups, attr := range seq {
current := out
for _, group := range groups {
if next, ok := current[group].(map[string]any); ok {
current = next
} else {
newMap := make(map[string]any)
current[group] = newMap
current = newMap
}
}
current[attr.Key] = attr.Value.Any()
}
return out
}
func JSONEncoder(attrs iter.Seq2[[]string, slog.Attr]) (string, error) {
m := ToMap(attrs)
if v, ok := m[slog.SourceKey]; ok {
pc := v.(uint64)
fs := runtime.CallersFrames([]uintptr{uintptr(pc)})
f, _ := fs.Next()
m[slog.SourceKey] = fmt.Sprintf("%s:%d", f.File, f.Line)
}
b, err := json.Marshal(m)
if err != nil {
return "", err
}
return string(b), nil
}
func MessageEncoder(attrs iter.Seq2[[]string, slog.Attr]) (string, error) {
for groups, attr := range attrs {
if len(groups) == 0 && attr.Key == slog.MessageKey {
return attr.Value.String(), nil
}
}
return "", nil
}
|