Skip to content

Commit 72fc0a7

Browse files
holimanDoozers
authored andcommitted
log: remove lazy, remove unused interfaces, unexport methods (ethereum#28622)
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) ```
1 parent 703b5ad commit 72fc0a7

File tree

11 files changed

+49
-116
lines changed

11 files changed

+49
-116
lines changed

cmd/geth/logtestcmd_active.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ This command is only meant for testing.
4343

4444
type customQuotedStringer struct {
4545
}
46+
4647
func (c customQuotedStringer) String() string {
4748
return "output with 'quotes'"
4849
}
@@ -80,8 +81,6 @@ func logTest(ctx *cli.Context) error {
8081
log.Info("uint64", "18,446,744,073,709,551,615", uint64(math.MaxUint64))
8182
}
8283
{ // Special characters
83-
84-
8584
log.Info("Special chars in value", "key", "special \r\n\t chars")
8685
log.Info("Special chars in key", "special \n\t chars", "value")
8786

@@ -103,9 +102,6 @@ func logTest(ctx *cli.Context) error {
103102
var c customQuotedStringer
104103
log.Info("a custom stringer that emits quoted text", "output", c)
105104
}
106-
{ // Lazy eval
107-
log.Info("Lazy evaluation of value", "key", log.Lazy{Fn: func() interface{} { return "lazy value" }})
108-
}
109105
{ // Multi-line message
110106
log.Info("A message with wonky \U0001F4A9 characters")
111107
log.Info("A multiline message \nINFO [10-18|14:11:31.106] with wonky characters \U0001F4A9")
@@ -166,6 +162,10 @@ func logTest(ctx *cli.Context) error {
166162
{ // Logging with 'reserved' keys
167163
log.Info("Using keys 't', 'lvl', 'time', 'level' and 'msg'", "t", "t", "time", "time", "lvl", "lvl", "level", "level", "msg", "msg")
168164
}
165+
{ // Logging with wrong attr-value pairs
166+
log.Info("Odd pair (1 attr)", "key")
167+
log.Info("Odd pair (3 attr)", "key", "value", "key2")
168+
}
169169
return nil
170170
}
171171

cmd/geth/testdata/logging/logtest-json.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
{"t":"2023-11-22T15:42:00.408197+08:00","lvl":"info","msg":"an error message with quotes","error":"this is an 'error'"}
2222
{"t":"2023-11-22T15:42:00.408202+08:00","lvl":"info","msg":"Custom Stringer value","2562047h47m16.854s":"2562047h47m16.854s"}
2323
{"t":"2023-11-22T15:42:00.408208+08:00","lvl":"info","msg":"a custom stringer that emits quoted text","output":"output with 'quotes'"}
24-
{"t":"2023-11-22T15:42:00.408215+08:00","lvl":"info","msg":"Lazy evaluation of value","key":"lazy value"}
2524
{"t":"2023-11-22T15:42:00.408219+08:00","lvl":"info","msg":"A message with wonky 💩 characters"}
2625
{"t":"2023-11-22T15:42:00.408222+08:00","lvl":"info","msg":"A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"}
2726
{"t":"2023-11-22T15:42:00.408226+08:00","lvl":"info","msg":"A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"}
@@ -49,3 +48,5 @@
4948
{"t":"2023-11-22T15:42:00.40835+08:00","lvl":"info","msg":"raw nil","res":null}
5049
{"t":"2023-11-22T15:42:00.408354+08:00","lvl":"info","msg":"(*uint64)(nil)","res":null}
5150
{"t":"2023-11-22T15:42:00.408361+08:00","lvl":"info","msg":"Using keys 't', 'lvl', 'time', 'level' and 'msg'","t":"t","time":"time","lvl":"lvl","level":"level","msg":"msg"}
51+
{"t":"2023-11-29T15:13:00.195655931+01:00","lvl":"info","msg":"Odd pair (1 attr)","key":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}
52+
{"t":"2023-11-29T15:13:00.195681832+01:00","lvl":"info","msg":"Odd pair (3 attr)","key":"value","key2":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}

cmd/geth/testdata/logging/logtest-logfmt.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="\x1b[35mColored\x1b[0m[" "\x1b[35mColor
2121
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="an error message with quotes" error="this is an 'error'"
2222
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Custom Stringer value" 2562047h47m16.854s=2562047h47m16.854s
2323
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="a custom stringer that emits quoted text" output="output with 'quotes'"
24-
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Lazy evaluation of value" key="lazy value"
2524
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A message with wonky 💩 characters"
2625
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
2726
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"
@@ -49,3 +48,5 @@ t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-custom-struct res=<nil>
4948
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="raw nil" res=<nil>
5049
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*uint64)(nil) res=<nil>
5150
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Using keys 't', 'lvl', 'time', 'level' and 'msg'" t=t time=time lvl=lvl level=level msg=msg
51+
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (1 attr)" key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
52+
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (3 attr)" key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

cmd/geth/testdata/logging/logtest-terminal.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ INFO [xx-xx|xx:xx:xx.xxx] "\x1b[35mColored\x1b[0m[" "\x1b[35mColo
2121
INFO [xx-xx|xx:xx:xx.xxx] an error message with quotes error="this is an 'error'"
2222
INFO [xx-xx|xx:xx:xx.xxx] Custom Stringer value 2562047h47m16.854s=2562047h47m16.854s
2323
INFO [xx-xx|xx:xx:xx.xxx] a custom stringer that emits quoted text output="output with 'quotes'"
24-
INFO [xx-xx|xx:xx:xx.xxx] Lazy evaluation of value key="lazy value"
25-
INFO [xx-xx|xx:xx:xx.xxx] "A message with wonky 💩 characters"
24+
INFO [xx-xx|xx:xx:xx.xxx] "A message with wonky 💩 characters"
2625
INFO [xx-xx|xx:xx:xx.xxx] "A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
2726
INFO [xx-xx|xx:xx:xx.xxx] A multiline message
2827
LALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above
@@ -50,3 +49,5 @@ INFO [xx-xx|xx:xx:xx.xxx] nil-custom-struct res=<nil>
5049
INFO [xx-xx|xx:xx:xx.xxx] raw nil res=<nil>
5150
INFO [xx-xx|xx:xx:xx.xxx] (*uint64)(nil) res=<nil>
5251
INFO [xx-xx|xx:xx:xx.xxx] Using keys 't', 'lvl', 'time', 'level' and 'msg' t=t time=time lvl=lvl level=level msg=msg
52+
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (1 attr) key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
53+
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (3 attr) key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

internal/testlog/testlog.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ func LoggerWithHandler(t *testing.T, handler slog.Handler) log.Logger {
100100

101101
func (l *logger) Write(level slog.Level, msg string, ctx ...interface{}) {}
102102

103+
func (l *logger) Enabled(ctx context.Context, level slog.Level) bool {
104+
return l.l.Enabled(ctx, level)
105+
}
106+
103107
func (l *logger) Trace(msg string, ctx ...interface{}) {
104108
l.t.Helper()
105109
l.mu.Lock()
@@ -183,7 +187,7 @@ func (h *bufHandler) terminalFormat(r slog.Record) string {
183187
}
184188

185189
for _, attr := range attrs {
186-
fmt.Fprintf(buf, " %s=%s", attr.Key, string(log.FormatSlogValue(attr.Value, true, nil)))
190+
fmt.Fprintf(buf, " %s=%s", attr.Key, string(log.FormatSlogValue(attr.Value, nil)))
187191
}
188192
buf.WriteByte('\n')
189193
return buf.String()

log/format.go

+12-43
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,14 @@ const (
2323
// 40 spaces
2424
var spaces = []byte(" ")
2525

26-
type Format interface {
27-
Format(r slog.Record) []byte
28-
}
29-
30-
// FormatFunc returns a new Format object which uses
31-
// the given function to perform record formatting.
32-
func FormatFunc(f func(slog.Record) []byte) Format {
33-
return formatFunc(f)
34-
}
35-
36-
type formatFunc func(slog.Record) []byte
37-
38-
func (f formatFunc) Format(r slog.Record) []byte {
39-
return f(r)
40-
}
41-
4226
// TerminalStringer is an analogous interface to the stdlib stringer, allowing
4327
// own types to have custom shortened serialization formats when printed to the
4428
// screen.
4529
type TerminalStringer interface {
4630
TerminalString() string
4731
}
4832

49-
func (h *TerminalHandler) TerminalFormat(buf []byte, r slog.Record, usecolor bool) []byte {
33+
func (h *TerminalHandler) format(buf []byte, r slog.Record, usecolor bool) []byte {
5034
msg := escapeMessage(r.Message)
5135
var color = ""
5236
if usecolor {
@@ -88,13 +72,13 @@ func (h *TerminalHandler) TerminalFormat(buf []byte, r slog.Record, usecolor boo
8872
if (r.NumAttrs()+len(h.attrs)) > 0 && length < termMsgJust {
8973
b.Write(spaces[:termMsgJust-length])
9074
}
91-
// print the keys logfmt style
92-
h.logfmt(b, r, color)
75+
// print the attributes
76+
h.formatAttributes(b, r, color)
9377

9478
return b.Bytes()
9579
}
9680

97-
func (h *TerminalHandler) logfmt(buf *bytes.Buffer, r slog.Record, color string) {
81+
func (h *TerminalHandler) formatAttributes(buf *bytes.Buffer, r slog.Record, color string) {
9882
// tmp is a temporary buffer we use, until bytes.Buffer.AvailableBuffer() (1.21)
9983
// can be used.
10084
var tmp = make([]byte, 40)
@@ -112,7 +96,7 @@ func (h *TerminalHandler) logfmt(buf *bytes.Buffer, r slog.Record, color string)
11296
buf.WriteByte('=')
11397
}
11498
//val := FormatSlogValue(attr.Value, true, buf.AvailableBuffer())
115-
val := FormatSlogValue(attr.Value, true, tmp[:0])
99+
val := FormatSlogValue(attr.Value, tmp[:0])
116100

117101
padding := h.fieldPadding[attr.Key]
118102

@@ -140,8 +124,8 @@ func (h *TerminalHandler) logfmt(buf *bytes.Buffer, r slog.Record, color string)
140124
buf.WriteByte('\n')
141125
}
142126

143-
// FormatSlogValue formats a slog.Value for serialization
144-
func FormatSlogValue(v slog.Value, term bool, tmp []byte) (result []byte) {
127+
// FormatSlogValue formats a slog.Value for serialization to terminal.
128+
func FormatSlogValue(v slog.Value, tmp []byte) (result []byte) {
145129
var value any
146130
defer func() {
147131
if err := recover(); err != nil {
@@ -156,11 +140,9 @@ func FormatSlogValue(v slog.Value, term bool, tmp []byte) (result []byte) {
156140
switch v.Kind() {
157141
case slog.KindString:
158142
return appendEscapeString(tmp, v.String())
159-
case slog.KindAny:
160-
value = v.Any()
161-
case slog.KindInt64: // All int-types (int8 ,int16 etc) wind up here
143+
case slog.KindInt64: // All int-types (int8, int16 etc) wind up here
162144
return appendInt64(tmp, v.Int64())
163-
case slog.KindUint64: // All uint-types (int8 ,int16 etc) wind up here
145+
case slog.KindUint64: // All uint-types (uint8, uint16 etc) wind up here
164146
return appendUint64(tmp, v.Uint64(), false)
165147
case slog.KindFloat64:
166148
return strconv.AppendFloat(tmp, v.Float64(), floatFormat, 3, 64)
@@ -180,27 +162,14 @@ func FormatSlogValue(v slog.Value, term bool, tmp []byte) (result []byte) {
180162
return []byte("<nil>")
181163
}
182164
switch v := value.(type) {
183-
case *big.Int:
184-
// Big ints get consumed by the Stringer clause, so we need to handle
185-
// them earlier on.
186-
if v == nil {
187-
return append(tmp, []byte("<nil>")...)
188-
}
165+
case *big.Int: // Need to be before fmt.Stringer-clause
189166
return appendBigInt(tmp, v)
190-
191-
case *uint256.Int:
192-
// Uint256s get consumed by the Stringer clause, so we need to handle
193-
// them earlier on.
194-
if v == nil {
195-
return append(tmp, []byte("<nil>")...)
196-
}
167+
case *uint256.Int: // Need to be before fmt.Stringer-clause
197168
return appendU256(tmp, v)
198169
case error:
199170
return appendEscapeString(tmp, v.Error())
200171
case TerminalStringer:
201-
if term {
202-
return appendEscapeString(tmp, v.TerminalString()) // Custom terminal stringer provided, use that
203-
}
172+
return appendEscapeString(tmp, v.TerminalString())
204173
case fmt.Stringer:
205174
return appendEscapeString(tmp, v.String())
206175
}

log/handler.go

+2-37
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,6 @@ import (
1313
"golang.org/x/exp/slog"
1414
)
1515

16-
// Lazy allows you to defer calculation of a logged value that is expensive
17-
// to compute until it is certain that it must be evaluated with the given filters.
18-
//
19-
// You may wrap any function which takes no arguments to Lazy. It may return any
20-
// number of values of any type.
21-
type Lazy struct {
22-
Fn interface{}
23-
}
24-
25-
func evaluateLazy(lz Lazy) (interface{}, error) {
26-
t := reflect.TypeOf(lz.Fn)
27-
28-
if t.Kind() != reflect.Func {
29-
return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
30-
}
31-
32-
if t.NumIn() > 0 {
33-
return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
34-
}
35-
36-
if t.NumOut() == 0 {
37-
return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
38-
}
39-
40-
value := reflect.ValueOf(lz.Fn)
41-
results := value.Call([]reflect.Value{})
42-
if len(results) == 1 {
43-
return results[0].Interface(), nil
44-
}
45-
values := make([]interface{}, len(results))
46-
for i, v := range results {
47-
values[i] = v.Interface()
48-
}
49-
return values, nil
50-
}
51-
5216
type discardHandler struct{}
5317

5418
// DiscardHandler returns a no-op handler
@@ -112,7 +76,7 @@ func NewTerminalHandlerWithLevel(wr io.Writer, lvl slog.Level, useColor bool) *T
11276
func (h *TerminalHandler) Handle(_ context.Context, r slog.Record) error {
11377
h.mu.Lock()
11478
defer h.mu.Unlock()
115-
buf := h.TerminalFormat(h.buf, r, h.useColor)
79+
buf := h.format(h.buf, r, h.useColor)
11680
h.wr.Write(buf)
11781
h.buf = buf[:0]
11882
return nil
@@ -149,6 +113,7 @@ func (l *leveler) Level() slog.Level {
149113
return l.minLevel
150114
}
151115

116+
// JSONHandler returns a handler which prints records in JSON format.
152117
func JSONHandler(wr io.Writer) slog.Handler {
153118
return slog.NewJSONHandler(wr, &slog.HandlerOptions{
154119
ReplaceAttr: builtinReplaceJSON,

log/logger.go

+8-20
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ type Logger interface {
134134

135135
// Write logs a message at the specified level
136136
Write(level slog.Level, msg string, attrs ...any)
137+
138+
// Enabled reports whether l emits log records at the given context and level.
139+
Enabled(ctx context.Context, level slog.Level) bool
137140
}
138141

139142
type logger struct {
@@ -159,26 +162,6 @@ func (l *logger) Write(level slog.Level, msg string, attrs ...any) {
159162
if len(attrs)%2 != 0 {
160163
attrs = append(attrs, nil, errorKey, "Normalized odd number of arguments by adding nil")
161164
}
162-
163-
// evaluate lazy values
164-
var hadErr bool
165-
for i := 1; i < len(attrs); i += 2 {
166-
lz, ok := attrs[i].(Lazy)
167-
if ok {
168-
v, err := evaluateLazy(lz)
169-
if err != nil {
170-
hadErr = true
171-
attrs[i] = err
172-
} else {
173-
attrs[i] = v
174-
}
175-
}
176-
}
177-
178-
if hadErr {
179-
attrs = append(attrs, errorKey, "bad lazy")
180-
}
181-
182165
r := slog.NewRecord(time.Now(), level, msg, pcs[0])
183166
r.Add(attrs...)
184167
l.inner.Handler().Handle(context.Background(), r)
@@ -196,6 +179,11 @@ func (l *logger) New(ctx ...interface{}) Logger {
196179
return l.With(ctx...)
197180
}
198181

182+
// Enabled reports whether l emits log records at the given context and level.
183+
func (l *logger) Enabled(ctx context.Context, level slog.Level) bool {
184+
return l.inner.Enabled(ctx, level)
185+
}
186+
199187
func (l *logger) Trace(msg string, ctx ...interface{}) {
200188
l.Write(LevelTrace, msg, ctx...)
201189
}

log/logger_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ func TestLoggerOutput(t *testing.T) {
107107
bigint = big.NewInt(100)
108108
nilbig *big.Int
109109
err = fmt.Errorf("Oh nooes it's crap")
110-
lazy = Lazy{Fn: func() interface{} { return "lazy value" }}
111110
smallUint = uint256.NewInt(500_000)
112111
bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff}
113112
)
@@ -126,13 +125,12 @@ func TestLoggerOutput(t *testing.T) {
126125
"struct", customA,
127126
"struct", customB,
128127
"ptrstruct", &customA,
129-
"lazy", lazy,
130128
"smalluint", smallUint,
131129
"bigUint", bigUint)
132130

133131
have := out.String()
134132
t.Logf("output %v", out.String())
135-
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}" lazy="lazy value" 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
133+
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
136134
`
137135
if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) {
138136
t.Errorf("Error\nhave: %q\nwant: %q", have, want)

p2p/discover/table.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package discover
2424

2525
import (
26+
"context"
2627
crand "crypto/rand"
2728
"encoding/binary"
2829
"fmt"
@@ -330,8 +331,10 @@ func (tab *Table) loadSeedNodes() {
330331
seeds = append(seeds, tab.nursery...)
331332
for i := range seeds {
332333
seed := seeds[i]
333-
age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) }}
334-
tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age)
334+
if tab.log.Enabled(context.Background(), log.LevelTrace) {
335+
age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP()))
336+
tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age)
337+
}
335338
tab.addSeenNode(seed)
336339
}
337340
}

p2p/msgrate/msgrate.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package msgrate
1919

2020
import (
21+
"context"
2122
"errors"
2223
"math"
2324
"sort"
@@ -410,7 +411,9 @@ func (t *Trackers) tune() {
410411

411412
t.tuned = time.Now()
412413
t.log.Debug("Recalculated msgrate QoS values", "rtt", t.roundtrip, "confidence", t.confidence, "ttl", t.targetTimeout(), "next", t.tuned.Add(t.roundtrip))
413-
t.log.Trace("Debug dump of mean capacities", "caps", log.Lazy{Fn: t.meanCapacities})
414+
if t.log.Enabled(context.Background(), log.LevelTrace) {
415+
t.log.Trace("Debug dump of mean capacities", "caps", t.meanCapacities())
416+
}
414417
}
415418

416419
// detune reduces the tracker's confidence in order to make fresh measurements

0 commit comments

Comments
 (0)