@@ -101,6 +101,18 @@ var severityName = []string{
101
101
fatalLog : "FATAL" ,
102
102
}
103
103
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
+
104
116
// loggerT is the default logger used by grpclog.
105
117
type loggerT struct {
106
118
m []* log.Logger
@@ -111,7 +123,7 @@ type loggerT struct {
111
123
func (g * loggerT ) output (severity int , s string ) {
112
124
sevStr := severityName [severity ]
113
125
if ! g .jsonFormat {
114
- g .m [severity ].Output (2 , fmt . Sprintf ( "%v: %v" , sevStr , s ) )
126
+ g .m [severity ].Output (2 , sevStr + ": " + s )
115
127
return
116
128
}
117
129
// TODO: we can also include the logging component, but that needs more
@@ -123,54 +135,78 @@ func (g *loggerT) output(severity int, s string) {
123
135
g .m [severity ].Output (2 , string (b ))
124
136
}
125
137
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
+
126
162
func (g * loggerT ) Info (args ... any ) {
127
- g .output (infoLog , fmt . Sprint ( args ... ) )
163
+ g .print (infoLog , args ... )
128
164
}
129
165
130
166
func (g * loggerT ) Infoln (args ... any ) {
131
- g .output (infoLog , fmt . Sprintln ( args ... ) )
167
+ g .println (infoLog , args ... )
132
168
}
133
169
134
170
func (g * loggerT ) Infof (format string , args ... any ) {
135
- g .output (infoLog , fmt . Sprintf ( format , args ... ) )
171
+ g .printf (infoLog , format , args ... )
136
172
}
137
173
138
174
func (g * loggerT ) Warning (args ... any ) {
139
- g .output (warningLog , fmt . Sprint ( args ... ) )
175
+ g .print (warningLog , args ... )
140
176
}
141
177
142
178
func (g * loggerT ) Warningln (args ... any ) {
143
- g .output (warningLog , fmt . Sprintln ( args ... ) )
179
+ g .println (warningLog , args ... )
144
180
}
145
181
146
182
func (g * loggerT ) Warningf (format string , args ... any ) {
147
- g .output (warningLog , fmt . Sprintf ( format , args ... ) )
183
+ g .printf (warningLog , format , args ... )
148
184
}
149
185
150
186
func (g * loggerT ) Error (args ... any ) {
151
- g .output (errorLog , fmt . Sprint ( args ... ) )
187
+ g .print (errorLog , args ... )
152
188
}
153
189
154
190
func (g * loggerT ) Errorln (args ... any ) {
155
- g .output (errorLog , fmt . Sprintln ( args ... ) )
191
+ g .println (errorLog , args ... )
156
192
}
157
193
158
194
func (g * loggerT ) Errorf (format string , args ... any ) {
159
- g .output (errorLog , fmt . Sprintf ( format , args ... ) )
195
+ g .printf (errorLog , format , args ... )
160
196
}
161
197
162
198
func (g * loggerT ) Fatal (args ... any ) {
163
- g .output (fatalLog , fmt . Sprint ( args ... ) )
199
+ g .print (fatalLog , args ... )
164
200
os .Exit (1 )
165
201
}
166
202
167
203
func (g * loggerT ) Fatalln (args ... any ) {
168
- g .output (fatalLog , fmt . Sprintln ( args ... ) )
204
+ g .println (fatalLog , args ... )
169
205
os .Exit (1 )
170
206
}
171
207
172
208
func (g * loggerT ) Fatalf (format string , args ... any ) {
173
- g .output (fatalLog , fmt . Sprintf ( format , args ... ) )
209
+ g .printf (fatalLog , format , args ... )
174
210
os .Exit (1 )
175
211
}
176
212
@@ -186,19 +222,42 @@ type LoggerV2Config struct {
186
222
FormatJSON bool
187
223
}
188
224
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
+
189
242
// NewLoggerV2 creates a new LoggerV2 instance with the provided configuration.
190
243
// The infoW, warningW, and errorW writers are used to write log messages of
191
244
// different severity levels.
192
245
func NewLoggerV2 (infoW , warningW , errorW io.Writer , c LoggerV2Config ) LoggerV2 {
193
- var m []* log.Logger
194
246
flag := log .LstdFlags
195
247
if c .FormatJSON {
196
248
flag = 0
197
249
}
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
+ }
203
262
return & loggerT {m : m , v : c .Verbosity , jsonFormat : c .FormatJSON }
204
263
}
0 commit comments