github.com/ethereum/go-ethereum@v1.16.1/log/logger_test.go (about) 1 package log 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "log/slog" 9 "math/big" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/holiman/uint256" 15 ) 16 17 // TestLoggingWithVmodule checks that vmodule works. 18 func TestLoggingWithVmodule(t *testing.T) { 19 out := new(bytes.Buffer) 20 glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false)) 21 glog.Verbosity(LevelCrit) 22 logger := NewLogger(glog) 23 logger.Warn("This should not be seen", "ignored", "true") 24 glog.Vmodule("logger_test.go=5") 25 logger.Trace("a message", "foo", "bar") 26 have := out.String() 27 // The timestamp is locale-dependent, so we want to trim that off 28 // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." 29 have = strings.Split(have, "]")[1] 30 want := " a message foo=bar\n" 31 if have != want { 32 t.Errorf("\nhave: %q\nwant: %q\n", have, want) 33 } 34 } 35 36 func TestTerminalHandlerWithAttrs(t *testing.T) { 37 out := new(bytes.Buffer) 38 glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false).WithAttrs([]slog.Attr{slog.String("baz", "bat")})) 39 glog.Verbosity(LevelTrace) 40 logger := NewLogger(glog) 41 logger.Trace("a message", "foo", "bar") 42 have := out.String() 43 // The timestamp is locale-dependent, so we want to trim that off 44 // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." 45 have = strings.Split(have, "]")[1] 46 want := " a message baz=bat foo=bar\n" 47 if have != want { 48 t.Errorf("\nhave: %q\nwant: %q\n", have, want) 49 } 50 } 51 52 // Make sure the default json handler outputs debug log lines 53 func TestJSONHandler(t *testing.T) { 54 out := new(bytes.Buffer) 55 handler := JSONHandler(out) 56 logger := slog.New(handler) 57 logger.Debug("hi there") 58 if len(out.String()) == 0 { 59 t.Error("expected non-empty debug log output from default JSON Handler") 60 } 61 62 out.Reset() 63 handler = JSONHandlerWithLevel(out, slog.LevelInfo) 64 logger = slog.New(handler) 65 logger.Debug("hi there") 66 if len(out.String()) != 0 { 67 t.Errorf("expected empty debug log output, but got: %v", out.String()) 68 } 69 } 70 71 func BenchmarkTraceLogging(b *testing.B) { 72 SetDefault(NewLogger(NewTerminalHandler(io.Discard, true))) 73 b.ResetTimer() 74 for i := 0; i < b.N; i++ { 75 Trace("a message", "v", i) 76 } 77 } 78 79 func BenchmarkTerminalHandler(b *testing.B) { 80 l := NewLogger(NewTerminalHandler(io.Discard, false)) 81 benchmarkLogger(b, l) 82 } 83 func BenchmarkLogfmtHandler(b *testing.B) { 84 l := NewLogger(LogfmtHandler(io.Discard)) 85 benchmarkLogger(b, l) 86 } 87 88 func BenchmarkJSONHandler(b *testing.B) { 89 l := NewLogger(JSONHandler(io.Discard)) 90 benchmarkLogger(b, l) 91 } 92 93 func benchmarkLogger(b *testing.B, l Logger) { 94 var ( 95 bb = make([]byte, 10) 96 tt = time.Now() 97 bigint = big.NewInt(100) 98 nilbig *big.Int 99 err = errors.New("oh nooes it's crap") 100 ) 101 b.ReportAllocs() 102 b.ResetTimer() 103 for i := 0; i < b.N; i++ { 104 l.Info("This is a message", 105 "foo", int16(i), 106 "bytes", bb, 107 "bonk", "a string with text", 108 "time", tt, 109 "bigint", bigint, 110 "nilbig", nilbig, 111 "err", err) 112 } 113 b.StopTimer() 114 } 115 116 func TestLoggerOutput(t *testing.T) { 117 type custom struct { 118 A string 119 B int8 120 } 121 var ( 122 customA = custom{"Foo", 12} 123 customB = custom{"Foo\nLinebreak", 122} 124 bb = make([]byte, 10) 125 tt = time.Time{} 126 bigint = big.NewInt(100) 127 nilbig *big.Int 128 err = errors.New("oh nooes it's crap") 129 smallUint = uint256.NewInt(500_000) 130 bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff} 131 ) 132 133 out := new(bytes.Buffer) 134 glogHandler := NewGlogHandler(NewTerminalHandler(out, false)) 135 glogHandler.Verbosity(LevelInfo) 136 NewLogger(glogHandler).Info("This is a message", 137 "foo", int16(123), 138 "bytes", bb, 139 "bonk", "a string with text", 140 "time", tt, 141 "bigint", bigint, 142 "nilbig", nilbig, 143 "err", err, 144 "struct", customA, 145 "struct", customB, 146 "ptrstruct", &customA, 147 "smalluint", smallUint, 148 "bigUint", bigUint) 149 150 have := out.String() 151 t.Logf("output %v", out.String()) 152 want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig=<nil> err="oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095 153 ` 154 if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) { 155 t.Errorf("Error\nhave: %q\nwant: %q", have, want) 156 } 157 } 158 159 const termTimeFormat = "01-02|15:04:05.000" 160 161 func BenchmarkAppendFormat(b *testing.B) { 162 var now = time.Now() 163 b.Run("fmt time.Format", func(b *testing.B) { 164 for i := 0; i < b.N; i++ { 165 fmt.Fprintf(io.Discard, "%s", now.Format(termTimeFormat)) 166 } 167 }) 168 b.Run("time.AppendFormat", func(b *testing.B) { 169 for i := 0; i < b.N; i++ { 170 now.AppendFormat(nil, termTimeFormat) 171 } 172 }) 173 var buf = new(bytes.Buffer) 174 b.Run("time.Custom", func(b *testing.B) { 175 for i := 0; i < b.N; i++ { 176 writeTimeTermFormat(buf, now) 177 buf.Reset() 178 } 179 }) 180 } 181 182 func TestTermTimeFormat(t *testing.T) { 183 var now = time.Now() 184 want := now.AppendFormat(nil, termTimeFormat) 185 var b = new(bytes.Buffer) 186 writeTimeTermFormat(b, now) 187 have := b.Bytes() 188 if !bytes.Equal(have, want) { 189 t.Errorf("have != want\nhave: %q\nwant: %q\n", have, want) 190 } 191 }