11package tint_test
22
33import (
4+ "context"
45 "errors"
6+ "io"
57 "os"
8+ "testing"
69 "time"
710
811 "github.com/lmittmann/tint"
@@ -21,3 +24,145 @@ func Example() {
2124 slog .Error ("DB connection lost" , tint .Err (errors .New ("connection reset" )), "db" , "myapp" )
2225 // Output:
2326}
27+
28+ // See https://github.com/golang/exp/blob/master/slog/benchmarks/benchmarks_test.go#L25
29+ //
30+ // Run e.g.:
31+ //
32+ // go test -bench=. -count=10 | benchstat -col /h /dev/stdin
33+ func BenchmarkLogAttrs (b * testing.B ) {
34+ handler := []struct {
35+ Name string
36+ H slog.Handler
37+ }{
38+ {"tint" , tint .NewHandler (io .Discard )},
39+ {"text" , slog .NewTextHandler (io .Discard )},
40+ {"json" , slog .NewJSONHandler (io .Discard )},
41+ {"discard" , new (discarder )},
42+ }
43+
44+ benchmarks := []struct {
45+ Name string
46+ F func (* slog.Logger )
47+ }{
48+ {
49+ "5 args" ,
50+ func (logger * slog.Logger ) {
51+ logger .LogAttrs (nil , slog .LevelInfo , testMessage ,
52+ slog .String ("string" , testString ),
53+ slog .Int ("status" , testInt ),
54+ slog .Duration ("duration" , testDuration ),
55+ slog .Time ("time" , testTime ),
56+ slog .Any ("error" , testError ),
57+ )
58+ },
59+ },
60+ {
61+ "5 args custom level" ,
62+ func (logger * slog.Logger ) {
63+ logger .LogAttrs (nil , slog .LevelInfo + 1 , testMessage ,
64+ slog .String ("string" , testString ),
65+ slog .Int ("status" , testInt ),
66+ slog .Duration ("duration" , testDuration ),
67+ slog .Time ("time" , testTime ),
68+ slog .Any ("error" , testError ),
69+ )
70+ },
71+ },
72+ {
73+ "10 args" ,
74+ func (logger * slog.Logger ) {
75+ logger .LogAttrs (nil , slog .LevelInfo , testMessage ,
76+ slog .String ("string" , testString ),
77+ slog .Int ("status" , testInt ),
78+ slog .Duration ("duration" , testDuration ),
79+ slog .Time ("time" , testTime ),
80+ slog .Any ("error" , testError ),
81+ slog .String ("string" , testString ),
82+ slog .Int ("status" , testInt ),
83+ slog .Duration ("duration" , testDuration ),
84+ slog .Time ("time" , testTime ),
85+ slog .Any ("error" , testError ),
86+ )
87+ },
88+ },
89+ {
90+ "40 args" ,
91+ func (logger * slog.Logger ) {
92+ logger .LogAttrs (nil , slog .LevelInfo , testMessage ,
93+ slog .String ("string" , testString ),
94+ slog .Int ("status" , testInt ),
95+ slog .Duration ("duration" , testDuration ),
96+ slog .Time ("time" , testTime ),
97+ slog .Any ("error" , testError ),
98+ slog .String ("string" , testString ),
99+ slog .Int ("status" , testInt ),
100+ slog .Duration ("duration" , testDuration ),
101+ slog .Time ("time" , testTime ),
102+ slog .Any ("error" , testError ),
103+ slog .String ("string" , testString ),
104+ slog .Int ("status" , testInt ),
105+ slog .Duration ("duration" , testDuration ),
106+ slog .Time ("time" , testTime ),
107+ slog .Any ("error" , testError ),
108+ slog .String ("string" , testString ),
109+ slog .Int ("status" , testInt ),
110+ slog .Duration ("duration" , testDuration ),
111+ slog .Time ("time" , testTime ),
112+ slog .Any ("error" , testError ),
113+ slog .String ("string" , testString ),
114+ slog .Int ("status" , testInt ),
115+ slog .Duration ("duration" , testDuration ),
116+ slog .Time ("time" , testTime ),
117+ slog .Any ("error" , testError ),
118+ slog .String ("string" , testString ),
119+ slog .Int ("status" , testInt ),
120+ slog .Duration ("duration" , testDuration ),
121+ slog .Time ("time" , testTime ),
122+ slog .Any ("error" , testError ),
123+ slog .String ("string" , testString ),
124+ slog .Int ("status" , testInt ),
125+ slog .Duration ("duration" , testDuration ),
126+ slog .Time ("time" , testTime ),
127+ slog .Any ("error" , testError ),
128+ slog .String ("string" , testString ),
129+ slog .Int ("status" , testInt ),
130+ slog .Duration ("duration" , testDuration ),
131+ slog .Time ("time" , testTime ),
132+ slog .Any ("error" , testError ),
133+ )
134+ },
135+ },
136+ }
137+
138+ for _ , h := range handler {
139+ b .Run ("h=" + h .Name , func (b * testing.B ) {
140+ for _ , bench := range benchmarks {
141+ b .Run (bench .Name , func (b * testing.B ) {
142+ b .ReportAllocs ()
143+ logger := slog .New (h .H )
144+ for i := 0 ; i < b .N ; i ++ {
145+ bench .F (logger )
146+ }
147+ })
148+ }
149+ })
150+ }
151+ }
152+
153+ // discarder is a slog.Handler that discards all records.
154+ type discarder struct {}
155+
156+ func (* discarder ) Enabled (context.Context , slog.Level ) bool { return true }
157+ func (* discarder ) Handle (context.Context , slog.Record ) error { return nil }
158+ func (d * discarder ) WithAttrs (attrs []slog.Attr ) slog.Handler { return d }
159+ func (d * discarder ) WithGroup (name string ) slog.Handler { return d }
160+
161+ var (
162+ testMessage = "Test logging, but use a somewhat realistic message length."
163+ testTime = time .Date (2022 , time .May , 1 , 0 , 0 , 0 , 0 , time .UTC )
164+ testString = "7e3b3b2aaeff56a7108fe11e154200dd/7819479873059528190"
165+ testInt = 32768
166+ testDuration = 23 * time .Second
167+ testError = errors .New ("fail" )
168+ )
0 commit comments