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