Skip to content

Commit 14acdf2

Browse files
committed
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 9ae7402 commit 14acdf2

File tree

10 files changed

+70
-128
lines changed

10 files changed

+70
-128
lines changed

internal/testlog/testlog.go

Lines changed: 5 additions & 1 deletion
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()

light/txpool.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,10 @@ func (p *TxPool) add(ctx context.Context, tx *types.Transaction) error {
450450
}
451451

452452
// Print a log message if low enough level is set
453-
log.Debug("Pooled new transaction", "hash", hash, "from", log.Lazy{Fn: func() common.Address { from, _ := types.Sender(p.signer, tx); return from }}, "to", tx.To())
453+
if log.Enabled(log.LevelDebug) {
454+
from, _ := types.Sender(p.signer, tx)
455+
log.Debug("Pooled new transaction", "hash", hash, "from", from, "to", tx.To())
456+
}
454457
return nil
455458
}
456459

log/format.go

Lines changed: 12 additions & 43 deletions
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

Lines changed: 2 additions & 37 deletions
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

Lines changed: 8 additions & 20 deletions
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

Lines changed: 1 addition & 3 deletions
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)

log/root.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package log
22

33
import (
4+
"context"
45
"os"
56
"sync/atomic"
67

@@ -115,3 +116,7 @@ func Crit(msg string, ctx ...interface{}) {
115116
func New(ctx ...interface{}) Logger {
116117
return Root().With(ctx...)
117118
}
119+
120+
func Enabled(level slog.Level) bool {
121+
return Root().Enabled(context.Background(), level)
122+
}

p2p/discover/table.go

Lines changed: 19 additions & 11 deletions
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
"errors"
@@ -72,7 +73,10 @@ type Table struct {
7273
rand *mrand.Rand // source of randomness, periodically reseeded
7374
ips netutil.DistinctNetSet
7475

75-
db *nodeDB // database of known nodes
76+
db *nodeDB // database of known nodes
77+
log log.Logger
78+
79+
// loop channels
7680
refreshReq chan chan struct{}
7781
initDone chan struct{}
7882
closeReq chan struct{}
@@ -118,9 +122,11 @@ func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string
118122
if err != nil {
119123
return nil, err
120124
}
125+
121126
tab := &Table{
122127
net: t,
123128
db: db,
129+
log: log.Root(),
124130
self: NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)),
125131
bonding: make(map[NodeID]*bondproc),
126132
bondslots: make(chan struct{}, maxBondingPingPongs),
@@ -322,10 +328,10 @@ func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node {
322328
// Bump the failure counter to detect and evacuate non-bonded entries
323329
fails := tab.db.findFails(n.ID) + 1
324330
tab.db.updateFindFails(n.ID, fails)
325-
log.Trace("Bumping findnode failure counter", "id", n.ID, "failcount", fails)
331+
tab.log.Trace("Bumping findnode failure counter", "id", n.ID, "failcount", fails)
326332

327333
if fails >= maxFindnodeFailures {
328-
log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails)
334+
tab.log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails)
329335
tab.delete(n)
330336
}
331337
}
@@ -455,8 +461,10 @@ func (tab *Table) loadSeedNodes(bond bool) {
455461
}
456462
for i := range seeds {
457463
seed := seeds[i]
458-
age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.bondTime(seed.ID)) }}
459-
log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age)
464+
if tab.log.Enabled(context.Background(), log.LevelTrace) {
465+
age := time.Since(tab.db.bondTime(seed.ID))
466+
tab.log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age)
467+
}
460468
tab.add(seed)
461469
}
462470
}
@@ -480,16 +488,16 @@ func (tab *Table) doRevalidate(done chan<- struct{}) {
480488
b := tab.buckets[bi]
481489
if err == nil {
482490
// The node responded, move it to the front.
483-
log.Debug("Revalidated node", "b", bi, "id", last.ID)
491+
tab.log.Debug("Revalidated node", "b", bi, "id", last.ID)
484492
b.bump(last)
485493
return
486494
}
487495
// No reply received, pick a replacement or delete the node if there aren't
488496
// any replacements.
489497
if r := tab.replace(b, last); r != nil {
490-
log.Debug("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP)
498+
tab.log.Debug("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP)
491499
} else {
492-
log.Debug("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP)
500+
tab.log.Debug("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP)
493501
}
494502
}
495503

@@ -599,7 +607,7 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
599607
age := time.Since(tab.db.bondTime(id))
600608
var result error
601609
if fails > 0 || age > nodeDBNodeExpiration {
602-
log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age)
610+
tab.log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age)
603611

604612
tab.bondmu.Lock()
605613
w := tab.bonding[id]
@@ -724,11 +732,11 @@ func (tab *Table) addIP(b *bucket, ip net.IP) bool {
724732
return true
725733
}
726734
if !tab.ips.Add(ip) {
727-
log.Debug("IP exceeds table limit", "ip", ip)
735+
tab.log.Debug("IP exceeds table limit", "ip", ip)
728736
return false
729737
}
730738
if !b.ips.Add(ip) {
731-
log.Debug("IP exceeds bucket limit", "ip", ip)
739+
tab.log.Debug("IP exceeds bucket limit", "ip", ip)
732740
tab.ips.Remove(ip)
733741
return false
734742
}

0 commit comments

Comments
 (0)