Source file
src/log/slog/handler.go
1
2
3
4
5 package slog
6
7 import (
8 "context"
9 "fmt"
10 "io"
11 "log/slog/internal/buffer"
12 "reflect"
13 "slices"
14 "strconv"
15 "sync"
16 "time"
17 )
18
19
20
21
22
23
24
25
26
27
28
29
30
31 type Handler interface {
32
33
34
35
36
37
38
39
40
41 Enabled(context.Context, Level) bool
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 Handle(context.Context, Record) error
61
62
63
64
65 WithAttrs(attrs []Attr) Handler
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 WithGroup(name string) Handler
87 }
88
89 type defaultHandler struct {
90 ch *commonHandler
91
92 output func(pc uintptr, data []byte) error
93 }
94
95 func newDefaultHandler(output func(uintptr, []byte) error) *defaultHandler {
96 return &defaultHandler{
97 ch: &commonHandler{json: false},
98 output: output,
99 }
100 }
101
102 func (*defaultHandler) Enabled(_ context.Context, l Level) bool {
103 return l >= logLoggerLevel.Level()
104 }
105
106
107
108
109 func (h *defaultHandler) Handle(ctx context.Context, r Record) error {
110 buf := buffer.New()
111 buf.WriteString(r.Level.String())
112 buf.WriteByte(' ')
113 buf.WriteString(r.Message)
114 state := h.ch.newHandleState(buf, true, " ")
115 defer state.free()
116 state.appendNonBuiltIns(r)
117 return h.output(r.PC, *buf)
118 }
119
120 func (h *defaultHandler) WithAttrs(as []Attr) Handler {
121 return &defaultHandler{h.ch.withAttrs(as), h.output}
122 }
123
124 func (h *defaultHandler) WithGroup(name string) Handler {
125 return &defaultHandler{h.ch.withGroup(name), h.output}
126 }
127
128
129
130 type HandlerOptions struct {
131
132
133 AddSource bool
134
135
136
137
138
139
140 Level Leveler
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 ReplaceAttr func(groups []string, a Attr) Attr
168 }
169
170
171 const (
172
173
174 TimeKey = "time"
175
176
177 LevelKey = "level"
178
179
180 MessageKey = "msg"
181
182
183 SourceKey = "source"
184 )
185
186 type commonHandler struct {
187 json bool
188 opts HandlerOptions
189 preformattedAttrs []byte
190
191
192
193
194 groupPrefix string
195 groups []string
196 nOpenGroups int
197 mu *sync.Mutex
198 w io.Writer
199 }
200
201 func (h *commonHandler) clone() *commonHandler {
202
203 return &commonHandler{
204 json: h.json,
205 opts: h.opts,
206 preformattedAttrs: slices.Clip(h.preformattedAttrs),
207 groupPrefix: h.groupPrefix,
208 groups: slices.Clip(h.groups),
209 nOpenGroups: h.nOpenGroups,
210 w: h.w,
211 mu: h.mu,
212 }
213 }
214
215
216
217 func (h *commonHandler) enabled(l Level) bool {
218 minLevel := LevelInfo
219 if h.opts.Level != nil {
220 minLevel = h.opts.Level.Level()
221 }
222 return l >= minLevel
223 }
224
225 func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
226
227
228 if countEmptyGroups(as) == len(as) {
229 return h
230 }
231 h2 := h.clone()
232
233 state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "")
234 defer state.free()
235 state.prefix.WriteString(h.groupPrefix)
236 if pfa := h2.preformattedAttrs; len(pfa) > 0 {
237 state.sep = h.attrSep()
238 if h2.json && pfa[len(pfa)-1] == '{' {
239 state.sep = ""
240 }
241 }
242
243 pos := state.buf.Len()
244 state.openGroups()
245 if !state.appendAttrs(as) {
246 state.buf.SetLen(pos)
247 } else {
248
249 h2.groupPrefix = state.prefix.String()
250
251
252 h2.nOpenGroups = len(h2.groups)
253 }
254 return h2
255 }
256
257 func (h *commonHandler) withGroup(name string) *commonHandler {
258 h2 := h.clone()
259 h2.groups = append(h2.groups, name)
260 return h2
261 }
262
263
264
265 func (h *commonHandler) handle(r Record) error {
266 state := h.newHandleState(buffer.New(), true, "")
267 defer state.free()
268 if h.json {
269 state.buf.WriteByte('{')
270 }
271
272 stateGroups := state.groups
273 state.groups = nil
274 rep := h.opts.ReplaceAttr
275
276 if !r.Time.IsZero() {
277 key := TimeKey
278 val := r.Time.Round(0)
279 if rep == nil {
280 state.appendKey(key)
281 state.appendTime(val)
282 } else {
283 state.appendAttr(Time(key, val))
284 }
285 }
286
287 key := LevelKey
288 val := r.Level
289 if rep == nil {
290 state.appendKey(key)
291 state.appendString(val.String())
292 } else {
293 state.appendAttr(Any(key, val))
294 }
295
296 if h.opts.AddSource {
297 state.appendAttr(Any(SourceKey, r.source()))
298 }
299 key = MessageKey
300 msg := r.Message
301 if rep == nil {
302 state.appendKey(key)
303 state.appendString(msg)
304 } else {
305 state.appendAttr(String(key, msg))
306 }
307 state.groups = stateGroups
308 state.appendNonBuiltIns(r)
309 state.buf.WriteByte('\n')
310
311 h.mu.Lock()
312 defer h.mu.Unlock()
313 _, err := h.w.Write(*state.buf)
314 return err
315 }
316
317 func (s *handleState) appendNonBuiltIns(r Record) {
318
319 if pfa := s.h.preformattedAttrs; len(pfa) > 0 {
320 s.buf.WriteString(s.sep)
321 s.buf.Write(pfa)
322 s.sep = s.h.attrSep()
323 if s.h.json && pfa[len(pfa)-1] == '{' {
324 s.sep = ""
325 }
326 }
327
328
329
330 nOpenGroups := s.h.nOpenGroups
331 if r.NumAttrs() > 0 {
332 s.prefix.WriteString(s.h.groupPrefix)
333
334
335
336
337 pos := s.buf.Len()
338 s.openGroups()
339 nOpenGroups = len(s.h.groups)
340 empty := true
341 r.Attrs(func(a Attr) bool {
342 if s.appendAttr(a) {
343 empty = false
344 }
345 return true
346 })
347 if empty {
348 s.buf.SetLen(pos)
349 nOpenGroups = s.h.nOpenGroups
350 }
351 }
352 if s.h.json {
353
354 for range s.h.groups[:nOpenGroups] {
355 s.buf.WriteByte('}')
356 }
357
358 s.buf.WriteByte('}')
359 }
360 }
361
362
363 func (h *commonHandler) attrSep() string {
364 if h.json {
365 return ","
366 }
367 return " "
368 }
369
370
371
372
373 type handleState struct {
374 h *commonHandler
375 buf *buffer.Buffer
376 freeBuf bool
377 sep string
378 prefix *buffer.Buffer
379 groups *[]string
380 }
381
382 var groupPool = sync.Pool{New: func() any {
383 s := make([]string, 0, 10)
384 return &s
385 }}
386
387 func (h *commonHandler) newHandleState(buf *buffer.Buffer, freeBuf bool, sep string) handleState {
388 s := handleState{
389 h: h,
390 buf: buf,
391 freeBuf: freeBuf,
392 sep: sep,
393 prefix: buffer.New(),
394 }
395 if h.opts.ReplaceAttr != nil {
396 s.groups = groupPool.Get().(*[]string)
397 *s.groups = append(*s.groups, h.groups[:h.nOpenGroups]...)
398 }
399 return s
400 }
401
402 func (s *handleState) free() {
403 if s.freeBuf {
404 s.buf.Free()
405 }
406 if gs := s.groups; gs != nil {
407 *gs = (*gs)[:0]
408 groupPool.Put(gs)
409 }
410 s.prefix.Free()
411 }
412
413 func (s *handleState) openGroups() {
414 for _, n := range s.h.groups[s.h.nOpenGroups:] {
415 s.openGroup(n)
416 }
417 }
418
419
420 const keyComponentSep = '.'
421
422
423
424 func (s *handleState) openGroup(name string) {
425 if s.h.json {
426 s.appendKey(name)
427 s.buf.WriteByte('{')
428 s.sep = ""
429 } else {
430 s.prefix.WriteString(name)
431 s.prefix.WriteByte(keyComponentSep)
432 }
433
434 if s.groups != nil {
435 *s.groups = append(*s.groups, name)
436 }
437 }
438
439
440 func (s *handleState) closeGroup(name string) {
441 if s.h.json {
442 s.buf.WriteByte('}')
443 } else {
444 (*s.prefix) = (*s.prefix)[:len(*s.prefix)-len(name)-1 ]
445 }
446 s.sep = s.h.attrSep()
447 if s.groups != nil {
448 *s.groups = (*s.groups)[:len(*s.groups)-1]
449 }
450 }
451
452
453
454 func (s *handleState) appendAttrs(as []Attr) bool {
455 nonEmpty := false
456 for _, a := range as {
457 if s.appendAttr(a) {
458 nonEmpty = true
459 }
460 }
461 return nonEmpty
462 }
463
464
465
466
467 func (s *handleState) appendAttr(a Attr) bool {
468 a.Value = a.Value.Resolve()
469 if rep := s.h.opts.ReplaceAttr; rep != nil && a.Value.Kind() != KindGroup {
470 var gs []string
471 if s.groups != nil {
472 gs = *s.groups
473 }
474
475 a = rep(gs, a)
476
477 a.Value = a.Value.Resolve()
478 }
479
480 if a.isEmpty() {
481 return false
482 }
483
484 if v := a.Value; v.Kind() == KindAny {
485 if src, ok := v.Any().(*Source); ok {
486 if s.h.json {
487 a.Value = src.group()
488 } else {
489 a.Value = StringValue(fmt.Sprintf("%s:%d", src.File, src.Line))
490 }
491 }
492 }
493 if a.Value.Kind() == KindGroup {
494 attrs := a.Value.Group()
495
496 if len(attrs) > 0 {
497
498
499
500
501 pos := s.buf.Len()
502
503 if a.Key != "" {
504 s.openGroup(a.Key)
505 }
506 if !s.appendAttrs(attrs) {
507 s.buf.SetLen(pos)
508 return false
509 }
510 if a.Key != "" {
511 s.closeGroup(a.Key)
512 }
513 }
514 } else {
515 s.appendKey(a.Key)
516 s.appendValue(a.Value)
517 }
518 return true
519 }
520
521 func (s *handleState) appendError(err error) {
522 s.appendString(fmt.Sprintf("!ERROR:%v", err))
523 }
524
525 func (s *handleState) appendKey(key string) {
526 s.buf.WriteString(s.sep)
527 if s.prefix != nil && len(*s.prefix) > 0 {
528
529 s.appendString(string(*s.prefix) + key)
530 } else {
531 s.appendString(key)
532 }
533 if s.h.json {
534 s.buf.WriteByte(':')
535 } else {
536 s.buf.WriteByte('=')
537 }
538 s.sep = s.h.attrSep()
539 }
540
541 func (s *handleState) appendString(str string) {
542 if s.h.json {
543 s.buf.WriteByte('"')
544 *s.buf = appendEscapedJSONString(*s.buf, str)
545 s.buf.WriteByte('"')
546 } else {
547
548 if needsQuoting(str) {
549 *s.buf = strconv.AppendQuote(*s.buf, str)
550 } else {
551 s.buf.WriteString(str)
552 }
553 }
554 }
555
556 func (s *handleState) appendValue(v Value) {
557 defer func() {
558 if r := recover(); r != nil {
559
560
561
562
563
564 if v := reflect.ValueOf(v.any); v.Kind() == reflect.Pointer && v.IsNil() {
565 s.appendString("<nil>")
566 return
567 }
568
569
570 s.appendString(fmt.Sprintf("!PANIC: %v", r))
571 }
572 }()
573
574 var err error
575 if s.h.json {
576 err = appendJSONValue(s, v)
577 } else {
578 err = appendTextValue(s, v)
579 }
580 if err != nil {
581 s.appendError(err)
582 }
583 }
584
585 func (s *handleState) appendTime(t time.Time) {
586 if s.h.json {
587 appendJSONTime(s, t)
588 } else {
589 *s.buf = appendRFC3339Millis(*s.buf, t)
590 }
591 }
592
593 func appendRFC3339Millis(b []byte, t time.Time) []byte {
594
595
596
597
598 const prefixLen = len("2006-01-02T15:04:05.000")
599 n := len(b)
600 t = t.Truncate(time.Millisecond).Add(time.Millisecond / 10)
601 b = t.AppendFormat(b, time.RFC3339Nano)
602 b = append(b[:n+prefixLen], b[n+prefixLen+1:]...)
603 return b
604 }
605
View as plain text