Skip to content

Commit 3931f73

Browse files
committed
Change logger to avoid Printf when disabled
Changes the logger to not call Printf when the logger is io.Discard. Also changes the logger constructor to use io.Discard instead of io.MultiWriter(io.Discard, io.Discard), which is necessary to detect all levels being discarded. Fixes #7463
1 parent a3a8657 commit 3931f73

File tree

2 files changed

+416
-28
lines changed

2 files changed

+416
-28
lines changed

grpclog/internal/loggerv2.go

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ var severityName = []string{
101101
fatalLog: "FATAL",
102102
}
103103

104+
// sprintf is fmt.Sprintf.
105+
// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily.
106+
var sprintf = fmt.Sprintf
107+
108+
// sprint is fmt.Sprint.
109+
// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily.
110+
var sprint = fmt.Sprint
111+
112+
// sprintln is fmt.Sprintln.
113+
// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily.
114+
var sprintln = fmt.Sprintln
115+
104116
// loggerT is the default logger used by grpclog.
105117
type loggerT struct {
106118
m []*log.Logger
@@ -111,7 +123,7 @@ type loggerT struct {
111123
func (g *loggerT) output(severity int, s string) {
112124
sevStr := severityName[severity]
113125
if !g.jsonFormat {
114-
g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s))
126+
g.m[severity].Output(2, sevStr+": "+s)
115127
return
116128
}
117129
// TODO: we can also include the logging component, but that needs more
@@ -123,54 +135,78 @@ func (g *loggerT) output(severity int, s string) {
123135
g.m[severity].Output(2, string(b))
124136
}
125137

138+
func (g *loggerT) printf(severity int, format string, args ...any) {
139+
// Note the discard check is duplicated in each print func, rather than in
140+
// output, to avoid the expensive Sprint calls.
141+
// De-duplicating this by moving to output would be a significant performance regression!
142+
if lg := g.m[severity]; lg.Writer() == io.Discard {
143+
return
144+
}
145+
g.output(severity, sprintf(format, args...))
146+
}
147+
148+
func (g *loggerT) print(severity int, v ...any) {
149+
if lg := g.m[severity]; lg.Writer() == io.Discard {
150+
return
151+
}
152+
g.output(severity, sprint(v...))
153+
}
154+
155+
func (g *loggerT) println(severity int, v ...any) {
156+
if lg := g.m[severity]; lg.Writer() == io.Discard {
157+
return
158+
}
159+
g.output(severity, sprintln(v...))
160+
}
161+
126162
func (g *loggerT) Info(args ...any) {
127-
g.output(infoLog, fmt.Sprint(args...))
163+
g.print(infoLog, args...)
128164
}
129165

130166
func (g *loggerT) Infoln(args ...any) {
131-
g.output(infoLog, fmt.Sprintln(args...))
167+
g.println(infoLog, args...)
132168
}
133169

134170
func (g *loggerT) Infof(format string, args ...any) {
135-
g.output(infoLog, fmt.Sprintf(format, args...))
171+
g.printf(infoLog, format, args...)
136172
}
137173

138174
func (g *loggerT) Warning(args ...any) {
139-
g.output(warningLog, fmt.Sprint(args...))
175+
g.print(warningLog, args...)
140176
}
141177

142178
func (g *loggerT) Warningln(args ...any) {
143-
g.output(warningLog, fmt.Sprintln(args...))
179+
g.println(warningLog, args...)
144180
}
145181

146182
func (g *loggerT) Warningf(format string, args ...any) {
147-
g.output(warningLog, fmt.Sprintf(format, args...))
183+
g.printf(warningLog, format, args...)
148184
}
149185

150186
func (g *loggerT) Error(args ...any) {
151-
g.output(errorLog, fmt.Sprint(args...))
187+
g.print(errorLog, args...)
152188
}
153189

154190
func (g *loggerT) Errorln(args ...any) {
155-
g.output(errorLog, fmt.Sprintln(args...))
191+
g.println(errorLog, args...)
156192
}
157193

158194
func (g *loggerT) Errorf(format string, args ...any) {
159-
g.output(errorLog, fmt.Sprintf(format, args...))
195+
g.printf(errorLog, format, args...)
160196
}
161197

162198
func (g *loggerT) Fatal(args ...any) {
163-
g.output(fatalLog, fmt.Sprint(args...))
199+
g.print(fatalLog, args...)
164200
os.Exit(1)
165201
}
166202

167203
func (g *loggerT) Fatalln(args ...any) {
168-
g.output(fatalLog, fmt.Sprintln(args...))
204+
g.println(fatalLog, args...)
169205
os.Exit(1)
170206
}
171207

172208
func (g *loggerT) Fatalf(format string, args ...any) {
173-
g.output(fatalLog, fmt.Sprintf(format, args...))
209+
g.printf(fatalLog, format, args...)
174210
os.Exit(1)
175211
}
176212

@@ -186,19 +222,42 @@ type LoggerV2Config struct {
186222
FormatJSON bool
187223
}
188224

225+
// combineLoggers returns a combined logger for both higher & lower severity logs,
226+
// or only one if the other is io.Discard.
227+
//
228+
// This uses io.Discard instead of io.MultiWriter when all loggers
229+
// are set to io.Discard. Both this package and the standard log package have
230+
// significant optimizations for io.Discard, which io.MultiWriter lacks (as of
231+
// this writing).
232+
func combineLoggers(lower, higher io.Writer) io.Writer {
233+
if lower == io.Discard {
234+
return higher
235+
}
236+
if higher == io.Discard {
237+
return lower
238+
}
239+
return io.MultiWriter(lower, higher)
240+
}
241+
189242
// NewLoggerV2 creates a new LoggerV2 instance with the provided configuration.
190243
// The infoW, warningW, and errorW writers are used to write log messages of
191244
// different severity levels.
192245
func NewLoggerV2(infoW, warningW, errorW io.Writer, c LoggerV2Config) LoggerV2 {
193-
var m []*log.Logger
194246
flag := log.LstdFlags
195247
if c.FormatJSON {
196248
flag = 0
197249
}
198-
m = append(m, log.New(infoW, "", flag))
199-
m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag))
200-
ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal.
201-
m = append(m, log.New(ew, "", flag))
202-
m = append(m, log.New(ew, "", flag))
250+
251+
warningW = combineLoggers(infoW, warningW)
252+
errorW = combineLoggers(errorW, warningW)
253+
254+
fatalW := errorW
255+
256+
m := []*log.Logger{
257+
log.New(infoW, "", flag),
258+
log.New(warningW, "", flag),
259+
log.New(errorW, "", flag),
260+
log.New(fatalW, "", flag),
261+
}
203262
return &loggerT{m: m, v: c.Verbosity, jsonFormat: c.FormatJSON}
204263
}

0 commit comments

Comments
 (0)