github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/log/slog/internal/benchmarks/handlers.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package benchmarks 6 7 // Handlers for benchmarking. 8 9 import ( 10 "context" 11 "fmt" 12 "io" 13 "log/slog" 14 "log/slog/internal/buffer" 15 "strconv" 16 "time" 17 ) 18 19 // A fastTextHandler writes a Record to an io.Writer in a format similar to 20 // slog.TextHandler, but without quoting or locking. It has a few other 21 // performance-motivated shortcuts, like writing times as seconds since the 22 // epoch instead of strings. 23 // 24 // It is intended to represent a high-performance Handler that synchronously 25 // writes text (as opposed to binary). 26 type fastTextHandler struct { 27 w io.Writer 28 } 29 30 func newFastTextHandler(w io.Writer) slog.Handler { 31 return &fastTextHandler{w: w} 32 } 33 34 func (h *fastTextHandler) Enabled(context.Context, slog.Level) bool { return true } 35 36 func (h *fastTextHandler) Handle(_ context.Context, r slog.Record) error { 37 buf := buffer.New() 38 defer buf.Free() 39 40 if !r.Time.IsZero() { 41 buf.WriteString("time=") 42 h.appendTime(buf, r.Time) 43 buf.WriteByte(' ') 44 } 45 buf.WriteString("level=") 46 *buf = strconv.AppendInt(*buf, int64(r.Level), 10) 47 buf.WriteByte(' ') 48 buf.WriteString("msg=") 49 buf.WriteString(r.Message) 50 r.Attrs(func(a slog.Attr) bool { 51 buf.WriteByte(' ') 52 buf.WriteString(a.Key) 53 buf.WriteByte('=') 54 h.appendValue(buf, a.Value) 55 return true 56 }) 57 buf.WriteByte('\n') 58 _, err := h.w.Write(*buf) 59 return err 60 } 61 62 func (h *fastTextHandler) appendValue(buf *buffer.Buffer, v slog.Value) { 63 switch v.Kind() { 64 case slog.KindString: 65 buf.WriteString(v.String()) 66 case slog.KindInt64: 67 *buf = strconv.AppendInt(*buf, v.Int64(), 10) 68 case slog.KindUint64: 69 *buf = strconv.AppendUint(*buf, v.Uint64(), 10) 70 case slog.KindFloat64: 71 *buf = strconv.AppendFloat(*buf, v.Float64(), 'g', -1, 64) 72 case slog.KindBool: 73 *buf = strconv.AppendBool(*buf, v.Bool()) 74 case slog.KindDuration: 75 *buf = strconv.AppendInt(*buf, v.Duration().Nanoseconds(), 10) 76 case slog.KindTime: 77 h.appendTime(buf, v.Time()) 78 case slog.KindAny: 79 a := v.Any() 80 switch a := a.(type) { 81 case error: 82 buf.WriteString(a.Error()) 83 default: 84 fmt.Fprint(buf, a) 85 } 86 default: 87 panic(fmt.Sprintf("bad kind: %s", v.Kind())) 88 } 89 } 90 91 func (h *fastTextHandler) appendTime(buf *buffer.Buffer, t time.Time) { 92 *buf = strconv.AppendInt(*buf, t.Unix(), 10) 93 } 94 95 func (h *fastTextHandler) WithAttrs([]slog.Attr) slog.Handler { 96 panic("fastTextHandler: With unimplemented") 97 } 98 99 func (*fastTextHandler) WithGroup(string) slog.Handler { 100 panic("fastTextHandler: WithGroup unimplemented") 101 } 102 103 // An asyncHandler simulates a Handler that passes Records to a 104 // background goroutine for processing. 105 // Because sending to a channel can be expensive due to locking, 106 // we simulate a lock-free queue by adding the Record to a ring buffer. 107 // Omitting the locking makes this little more than a copy of the Record, 108 // but that is a worthwhile thing to measure because Records are on the large 109 // side. Since nothing actually reads from the ring buffer, it can handle an 110 // arbitrary number of Records without either blocking or allocation. 111 type asyncHandler struct { 112 ringBuffer [100]slog.Record 113 next int 114 } 115 116 func newAsyncHandler() *asyncHandler { 117 return &asyncHandler{} 118 } 119 120 func (*asyncHandler) Enabled(context.Context, slog.Level) bool { return true } 121 122 func (h *asyncHandler) Handle(_ context.Context, r slog.Record) error { 123 h.ringBuffer[h.next] = r.Clone() 124 h.next = (h.next + 1) % len(h.ringBuffer) 125 return nil 126 } 127 128 func (*asyncHandler) WithAttrs([]slog.Attr) slog.Handler { 129 panic("asyncHandler: With unimplemented") 130 } 131 132 func (*asyncHandler) WithGroup(string) slog.Handler { 133 panic("asyncHandler: WithGroup unimplemented") 134 } 135 136 // A disabledHandler's Enabled method always returns false. 137 type disabledHandler struct{} 138 139 func (disabledHandler) Enabled(context.Context, slog.Level) bool { return false } 140 func (disabledHandler) Handle(context.Context, slog.Record) error { panic("should not be called") } 141 142 func (disabledHandler) WithAttrs([]slog.Attr) slog.Handler { 143 panic("disabledHandler: With unimplemented") 144 } 145 146 func (disabledHandler) WithGroup(string) slog.Handler { 147 panic("disabledHandler: WithGroup unimplemented") 148 }