-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathentry_bench_test.go
More file actions
157 lines (132 loc) · 3.87 KB
/
entry_bench_test.go
File metadata and controls
157 lines (132 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package logrus_test
import (
"errors"
"io"
"testing"
"github.com/sirupsen/logrus"
)
func BenchmarkEntry_WithError(b *testing.B) {
base := &logrus.Entry{Data: logrus.Fields{"a": 1}}
errBoom := errors.New("boom")
b.ReportAllocs()
b.ResetTimer()
for range b.N {
_ = base.WithError(errBoom)
}
}
func BenchmarkEntry_WithField_Chain(b *testing.B) {
base := &logrus.Entry{Data: logrus.Fields{"a": 1}}
errBoom := errors.New("boom")
b.ReportAllocs()
b.ResetTimer()
for range b.N {
e := base
e = e.WithField("k0", 0)
e = e.WithField("k1", 1)
e = e.WithField("k2", 2)
e = e.WithField("k3", 3)
e = e.WithError(errBoom)
_ = e
}
}
func BenchmarkEntry_WithFields(b *testing.B) {
fn := func() {}
fnPtr := &fn
tests := []struct {
name string
base logrus.Fields
fields logrus.Fields
}{
{
name: "valid_fields_only",
base: logrus.Fields{"a": 1, "b": "two"},
fields: logrus.Fields{"c": 3, "d": "four"},
},
{
name: "contains_func",
base: logrus.Fields{"a": 1},
fields: logrus.Fields{"bad": fn},
},
{
name: "contains_func_ptr",
base: logrus.Fields{"a": 1},
fields: logrus.Fields{"bad": fnPtr},
},
{
name: "mixed_valid_invalid",
base: logrus.Fields{"a": 1, "b": 2},
fields: logrus.Fields{"c": 3, "bad": fn, "d": 4},
},
{
name: "larger_map",
base: logrus.Fields{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7, "h": 8, "i": 9, "j": 10},
fields: logrus.Fields{"k": 11, "l": 12, "m": 13, "n": 14, "o": 15},
},
}
for _, tc := range tests {
b.Run(tc.name, func(b *testing.B) {
b.ReportAllocs()
e := &logrus.Entry{Data: tc.base}
b.ResetTimer()
for range b.N {
_ = e.WithFields(tc.fields)
}
})
}
}
func benchmarkEntryInfo(b *testing.B, reportCaller bool) {
// JSONFormatter is used intentionally to measure realistic end-to-end
// ReportCaller overhead (Entry.log + caller field formatting),
// not getCaller() in isolation.
logger := logrus.New()
logger.SetFormatter(&logrus.JSONFormatter{})
logger.SetReportCaller(reportCaller)
logger.SetLevel(logrus.InfoLevel) // ensure Info is enabled
logger.SetOutput(io.Discard)
entry := logrus.NewEntry(logger)
// getCaller has a package-level sync.Once; exclude initialization from the benchmark.
entry.Info("warmup")
b.ReportAllocs()
b.ResetTimer()
for range b.N {
entry.Info("test message")
}
}
func BenchmarkEntry_ReportCaller_NoCaller(b *testing.B) { benchmarkEntryInfo(b, false) }
func BenchmarkEntry_ReportCaller_WithCaller(b *testing.B) { benchmarkEntryInfo(b, true) }
//go:noinline
func caller4(entry *logrus.Entry) { caller3(entry) }
//go:noinline
func caller3(entry *logrus.Entry) { caller2(entry) }
//go:noinline
func caller2(entry *logrus.Entry) { caller1(entry) }
//go:noinline
func caller1(entry *logrus.Entry) { entry.Info("test message") }
// benchmarkEntryReportCallerDepth4 simulates a wrapper call site.
// It does not increase getCaller() scan depth (which stops at the first
// non-logrus frame), but ensures ReportCaller overhead is stable with
// wrapper layers.
func benchmarkEntryReportCallerDepth4(b *testing.B, reportCaller bool) {
// JSONFormatter is used intentionally to measure realistic end-to-end
// ReportCaller overhead (Entry.log + caller field formatting),
// not getCaller() in isolation.
logger := logrus.New()
logger.SetFormatter(&logrus.JSONFormatter{})
logger.SetReportCaller(reportCaller)
logger.SetLevel(logrus.InfoLevel)
logger.SetOutput(io.Discard)
entry := logrus.NewEntry(logger)
// getCaller has a package-level sync.Once; exclude initialization from the benchmark.
entry.Info("warmup")
b.ReportAllocs()
b.ResetTimer()
for range b.N {
caller4(entry)
}
}
func BenchmarkEntry_ReportCaller_NoCaller_Depth4(b *testing.B) {
benchmarkEntryReportCallerDepth4(b, false)
}
func BenchmarkEntry_ReportCaller_WithCaller_Depth4(b *testing.B) {
benchmarkEntryReportCallerDepth4(b, true)
}