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  }