b8d44ed98b
This change - Removes interface `log.Format`, - Removes method `log.FormatFunc`, - unexports `TerminalHandler.TerminalFormat` formatting methods (renamed to `TerminalHandler.format`) - removes the notion of `log.Lazy` values The lazy handler was useful in the old log package, since it could defer the evaluation of costly attributes until later in the log pipeline: thus, if the logging was done at 'Trace', we could skip evaluation if logging only was set to 'Info'. With the move to slog, this way of deferring evaluation is no longer needed, since slog introduced 'Enabled': the caller can thus do the evaluate-or-not decision at the callsite, which is much more straight-forward than dealing with lazy reflect-based evaluation. Also, lazy evaluation would not work with 'native' slog, as in, these two statements would be evaluated differently: ```golang log.Info("foo", "my lazy", lazyObj) slog.Info("foo", "my lazy", lazyObj) ```
173 lines
4.6 KiB
Go
173 lines
4.6 KiB
Go
package log
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"math/big"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/holiman/uint256"
|
|
"golang.org/x/exp/slog"
|
|
)
|
|
|
|
// TestLoggingWithVmodule checks that vmodule works.
|
|
func TestLoggingWithVmodule(t *testing.T) {
|
|
out := new(bytes.Buffer)
|
|
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false))
|
|
glog.Verbosity(LevelCrit)
|
|
logger := NewLogger(glog)
|
|
logger.Warn("This should not be seen", "ignored", "true")
|
|
glog.Vmodule("logger_test.go=5")
|
|
logger.Trace("a message", "foo", "bar")
|
|
have := out.String()
|
|
// The timestamp is locale-dependent, so we want to trim that off
|
|
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
|
have = strings.Split(have, "]")[1]
|
|
want := " a message foo=bar\n"
|
|
if have != want {
|
|
t.Errorf("\nhave: %q\nwant: %q\n", have, want)
|
|
}
|
|
}
|
|
|
|
func TestTerminalHandlerWithAttrs(t *testing.T) {
|
|
out := new(bytes.Buffer)
|
|
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false).WithAttrs([]slog.Attr{slog.String("baz", "bat")}))
|
|
glog.Verbosity(LevelTrace)
|
|
logger := NewLogger(glog)
|
|
logger.Trace("a message", "foo", "bar")
|
|
have := out.String()
|
|
// The timestamp is locale-dependent, so we want to trim that off
|
|
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
|
have = strings.Split(have, "]")[1]
|
|
want := " a message baz=bat foo=bar\n"
|
|
if have != want {
|
|
t.Errorf("\nhave: %q\nwant: %q\n", have, want)
|
|
}
|
|
}
|
|
|
|
func BenchmarkTraceLogging(b *testing.B) {
|
|
SetDefault(NewLogger(NewTerminalHandler(os.Stderr, true)))
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
Trace("a message", "v", i)
|
|
}
|
|
}
|
|
|
|
func BenchmarkTerminalHandler(b *testing.B) {
|
|
l := NewLogger(NewTerminalHandler(io.Discard, false))
|
|
benchmarkLogger(b, l)
|
|
}
|
|
func BenchmarkLogfmtHandler(b *testing.B) {
|
|
l := NewLogger(LogfmtHandler(io.Discard))
|
|
benchmarkLogger(b, l)
|
|
}
|
|
|
|
func BenchmarkJSONHandler(b *testing.B) {
|
|
l := NewLogger(JSONHandler(io.Discard))
|
|
benchmarkLogger(b, l)
|
|
}
|
|
|
|
func benchmarkLogger(b *testing.B, l Logger) {
|
|
var (
|
|
bb = make([]byte, 10)
|
|
tt = time.Now()
|
|
bigint = big.NewInt(100)
|
|
nilbig *big.Int
|
|
err = fmt.Errorf("Oh nooes it's crap")
|
|
)
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
l.Info("This is a message",
|
|
"foo", int16(i),
|
|
"bytes", bb,
|
|
"bonk", "a string with text",
|
|
"time", tt,
|
|
"bigint", bigint,
|
|
"nilbig", nilbig,
|
|
"err", err)
|
|
}
|
|
b.StopTimer()
|
|
}
|
|
|
|
func TestLoggerOutput(t *testing.T) {
|
|
type custom struct {
|
|
A string
|
|
B int8
|
|
}
|
|
var (
|
|
customA = custom{"Foo", 12}
|
|
customB = custom{"Foo\nLinebreak", 122}
|
|
bb = make([]byte, 10)
|
|
tt = time.Time{}
|
|
bigint = big.NewInt(100)
|
|
nilbig *big.Int
|
|
err = fmt.Errorf("Oh nooes it's crap")
|
|
smallUint = uint256.NewInt(500_000)
|
|
bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff}
|
|
)
|
|
|
|
out := new(bytes.Buffer)
|
|
glogHandler := NewGlogHandler(NewTerminalHandler(out, false))
|
|
glogHandler.Verbosity(LevelInfo)
|
|
NewLogger(glogHandler).Info("This is a message",
|
|
"foo", int16(123),
|
|
"bytes", bb,
|
|
"bonk", "a string with text",
|
|
"time", tt,
|
|
"bigint", bigint,
|
|
"nilbig", nilbig,
|
|
"err", err,
|
|
"struct", customA,
|
|
"struct", customB,
|
|
"ptrstruct", &customA,
|
|
"smalluint", smallUint,
|
|
"bigUint", bigUint)
|
|
|
|
have := out.String()
|
|
t.Logf("output %v", out.String())
|
|
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
|
|
`
|
|
if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) {
|
|
t.Errorf("Error\nhave: %q\nwant: %q", have, want)
|
|
}
|
|
}
|
|
|
|
const termTimeFormat = "01-02|15:04:05.000"
|
|
|
|
func BenchmarkAppendFormat(b *testing.B) {
|
|
var now = time.Now()
|
|
b.Run("fmt time.Format", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
fmt.Fprintf(io.Discard, "%s", now.Format(termTimeFormat))
|
|
}
|
|
})
|
|
b.Run("time.AppendFormat", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
now.AppendFormat(nil, termTimeFormat)
|
|
}
|
|
})
|
|
var buf = new(bytes.Buffer)
|
|
b.Run("time.Custom", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
writeTimeTermFormat(buf, now)
|
|
buf.Reset()
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestTermTimeFormat(t *testing.T) {
|
|
var now = time.Now()
|
|
want := now.AppendFormat(nil, termTimeFormat)
|
|
var b = new(bytes.Buffer)
|
|
writeTimeTermFormat(b, now)
|
|
have := b.Bytes()
|
|
if !bytes.Equal(have, want) {
|
|
t.Errorf("have != want\nhave: %q\nwant: %q\n", have, want)
|
|
}
|
|
}
|