...
Source file
src/log/slog/record.go
1
2
3
4
5 package slog
6
7 import (
8 "runtime"
9 "slices"
10 "time"
11 )
12
13 const nAttrsInline = 5
14
15
16
17
18
19
20 type Record struct {
21
22 Time time.Time
23
24
25 Message string
26
27
28 Level Level
29
30
31
32
33
34
35
36 PC uintptr
37
38
39
40
41 front [nAttrsInline]Attr
42
43
44 nFront int
45
46
47
48
49
50 back []Attr
51 }
52
53
54
55
56
57
58 func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record {
59 return Record{
60 Time: t,
61 Message: msg,
62 Level: level,
63 PC: pc,
64 }
65 }
66
67
68
69
70 func (r Record) Clone() Record {
71 r.back = slices.Clip(r.back)
72 return r
73 }
74
75
76 func (r Record) NumAttrs() int {
77 return r.nFront + len(r.back)
78 }
79
80
81
82 func (r Record) Attrs(f func(Attr) bool) {
83 for i := 0; i < r.nFront; i++ {
84 if !f(r.front[i]) {
85 return
86 }
87 }
88 for _, a := range r.back {
89 if !f(a) {
90 return
91 }
92 }
93 }
94
95
96
97 func (r *Record) AddAttrs(attrs ...Attr) {
98 var i int
99 for i = 0; i < len(attrs) && r.nFront < len(r.front); i++ {
100 a := attrs[i]
101 if a.Value.isEmptyGroup() {
102 continue
103 }
104 r.front[r.nFront] = a
105 r.nFront++
106 }
107
108
109 if cap(r.back) > len(r.back) {
110 end := r.back[:len(r.back)+1][len(r.back)]
111 if !end.isEmpty() {
112
113 r.back = slices.Clip(r.back)
114 r.back = append(r.back, String("!BUG", "AddAttrs unsafely called on copy of Record made without using Record.Clone"))
115 }
116 }
117 ne := countEmptyGroups(attrs[i:])
118 r.back = slices.Grow(r.back, len(attrs[i:])-ne)
119 for _, a := range attrs[i:] {
120 if !a.Value.isEmptyGroup() {
121 r.back = append(r.back, a)
122 }
123 }
124 }
125
126
127
128
129 func (r *Record) Add(args ...any) {
130 var a Attr
131 for len(args) > 0 {
132 a, args = argsToAttr(args)
133 if a.Value.isEmptyGroup() {
134 continue
135 }
136 if r.nFront < len(r.front) {
137 r.front[r.nFront] = a
138 r.nFront++
139 } else {
140 if r.back == nil {
141 r.back = make([]Attr, 0, countAttrs(args)+1)
142 }
143 r.back = append(r.back, a)
144 }
145 }
146 }
147
148
149 func countAttrs(args []any) int {
150 n := 0
151 for i := 0; i < len(args); i++ {
152 n++
153 if _, ok := args[i].(string); ok {
154 i++
155 }
156 }
157 return n
158 }
159
160 const badKey = "!BADKEY"
161
162
163
164
165
166
167
168 func argsToAttr(args []any) (Attr, []any) {
169 switch x := args[0].(type) {
170 case string:
171 if len(args) == 1 {
172 return String(badKey, x), nil
173 }
174 return Any(x, args[1]), args[2:]
175
176 case Attr:
177 return x, args[1:]
178
179 default:
180 return Any(badKey, x), args[1:]
181 }
182 }
183
184
185 type Source struct {
186
187
188
189 Function string `json:"function"`
190
191
192 File string `json:"file"`
193 Line int `json:"line"`
194 }
195
196
197
198
199
200 func (s *Source) group() Value {
201 var as []Attr
202 if s.Function != "" {
203 as = append(as, String("function", s.Function))
204 }
205 if s.File != "" {
206 as = append(as, String("file", s.File))
207 }
208 if s.Line != 0 {
209 as = append(as, Int("line", s.Line))
210 }
211 return GroupValue(as...)
212 }
213
214
215
216
217
218 func (r Record) source() *Source {
219 fs := runtime.CallersFrames([]uintptr{r.PC})
220 f, _ := fs.Next()
221 return &Source{
222 Function: f.Function,
223 File: f.File,
224 Line: f.Line,
225 }
226 }
227
View as plain text