Skip to content

Commit 2da8a55

Browse files
committed
log: make use of fmt.Append functionality
Since log is already responsible for managing its own buffers it is unfortunate that it calls fmt.Sprintf, which allocates, only to append that intermediate string to another buffer. Instead, use the new fmt.Append variants and avoid the allocation. We modify Logger.Output to wrap an internal Logger.output, which can be configured to use a particular append function. Logger.output is called from all the other functionality instead. This has the further advantage of simplifying the isDiscard check, which occurs to avoid the costly fmt.Print call. We coalesce all 6 checks as just 1 check in Logger.output. Also, swap the declaration order of Logger.Print and Logger.Printf to match the ordering elsewhere in the file. Performance: name old time/op new time/op delta Println 188ns ± 2% 172ns ± 4% -8.39% (p=0.000 n=10+10) PrintlnNoFlags 139ns ± 1% 116ns ± 1% -16.71% (p=0.000 n=9+9) name old allocs/op new allocs/op delta Println 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) PrintlnNoFlags 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Change-Id: I79d0ee404df848beb3626fe863ccc73a3e2eb325 Reviewed-on: https://go-review.googlesource.com/c/go/+/464345 Reviewed-by: Rob Pike <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Run-TryBot: Joseph Tsai <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 25f5d9d commit 2da8a55

File tree

2 files changed

+47
-30
lines changed

2 files changed

+47
-30
lines changed

src/log/log.go

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ func putBuffer(p *[]byte) {
190190
// provided for generality, although at the moment on all pre-defined
191191
// paths it will be 2.
192192
func (l *Logger) Output(calldepth int, s string) error {
193+
calldepth++ // +1 for this frame.
194+
return l.output(calldepth, func(b []byte) []byte {
195+
return append(b, s...)
196+
})
197+
}
198+
199+
func (l *Logger) output(calldepth int, appendOutput func([]byte) []byte) error {
200+
if l.isDiscard.Load() {
201+
return nil
202+
}
203+
193204
now := time.Now() // get this early.
194205

195206
// Load prefix and flag once so that their value is consistent within
@@ -211,7 +222,9 @@ func (l *Logger) Output(calldepth int, s string) error {
211222
buf := getBuffer()
212223
defer putBuffer(buf)
213224
formatHeader(buf, now, prefix, flag, file, line)
214-
*buf = append(*buf, s...)
225+
headerLen := len(*buf)
226+
*buf = appendOutput(*buf)
227+
s := (*buf)[headerLen:]
215228
if len(s) == 0 || s[len(s)-1] != '\n' {
216229
*buf = append(*buf, '\n')
217230
}
@@ -222,31 +235,28 @@ func (l *Logger) Output(calldepth int, s string) error {
222235
return err
223236
}
224237

225-
// Printf calls l.Output to print to the logger.
226-
// Arguments are handled in the manner of fmt.Printf.
227-
func (l *Logger) Printf(format string, v ...any) {
228-
if l.isDiscard.Load() {
229-
return
230-
}
231-
l.Output(2, fmt.Sprintf(format, v...))
232-
}
233-
234238
// Print calls l.Output to print to the logger.
235239
// Arguments are handled in the manner of fmt.Print.
236240
func (l *Logger) Print(v ...any) {
237-
if l.isDiscard.Load() {
238-
return
239-
}
240-
l.Output(2, fmt.Sprint(v...))
241+
l.output(2, func(b []byte) []byte {
242+
return fmt.Append(b, v...)
243+
})
244+
}
245+
246+
// Printf calls l.Output to print to the logger.
247+
// Arguments are handled in the manner of fmt.Printf.
248+
func (l *Logger) Printf(format string, v ...any) {
249+
l.output(2, func(b []byte) []byte {
250+
return fmt.Appendf(b, format, v...)
251+
})
241252
}
242253

243254
// Println calls l.Output to print to the logger.
244255
// Arguments are handled in the manner of fmt.Println.
245256
func (l *Logger) Println(v ...any) {
246-
if l.isDiscard.Load() {
247-
return
248-
}
249-
l.Output(2, fmt.Sprintln(v...))
257+
l.output(2, func(b []byte) []byte {
258+
return fmt.Appendln(b, v...)
259+
})
250260
}
251261

252262
// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
@@ -357,28 +367,25 @@ func Writer() io.Writer {
357367
// Print calls Output to print to the standard logger.
358368
// Arguments are handled in the manner of fmt.Print.
359369
func Print(v ...any) {
360-
if std.isDiscard.Load() {
361-
return
362-
}
363-
std.Output(2, fmt.Sprint(v...))
370+
std.output(2, func(b []byte) []byte {
371+
return fmt.Append(b, v...)
372+
})
364373
}
365374

366375
// Printf calls Output to print to the standard logger.
367376
// Arguments are handled in the manner of fmt.Printf.
368377
func Printf(format string, v ...any) {
369-
if std.isDiscard.Load() {
370-
return
371-
}
372-
std.Output(2, fmt.Sprintf(format, v...))
378+
std.output(2, func(b []byte) []byte {
379+
return fmt.Appendf(b, format, v...)
380+
})
373381
}
374382

375383
// Println calls Output to print to the standard logger.
376384
// Arguments are handled in the manner of fmt.Println.
377385
func Println(v ...any) {
378-
if std.isDiscard.Load() {
379-
return
380-
}
381-
std.Output(2, fmt.Sprintln(v...))
386+
std.output(2, func(b []byte) []byte {
387+
return fmt.Appendln(b, v...)
388+
})
382389
}
383390

384391
// Fatal is equivalent to Print() followed by a call to os.Exit(1).

src/log/log_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ func BenchmarkPrintln(b *testing.B) {
217217
const testString = "test"
218218
var buf bytes.Buffer
219219
l := New(&buf, "", LstdFlags)
220+
b.ReportAllocs()
220221
for i := 0; i < b.N; i++ {
221222
buf.Reset()
222223
l.Println(testString)
@@ -227,6 +228,7 @@ func BenchmarkPrintlnNoFlags(b *testing.B) {
227228
const testString = "test"
228229
var buf bytes.Buffer
229230
l := New(&buf, "", 0)
231+
b.ReportAllocs()
230232
for i := 0; i < b.N; i++ {
231233
buf.Reset()
232234
l.Println(testString)
@@ -255,3 +257,11 @@ func BenchmarkConcurrent(b *testing.B) {
255257
}
256258
group.Wait()
257259
}
260+
261+
func BenchmarkDiscard(b *testing.B) {
262+
l := New(io.Discard, "", LstdFlags|Lshortfile)
263+
b.ReportAllocs()
264+
for i := 0; i < b.N; i++ {
265+
l.Printf("processing %d objects from bucket %q", 1234, "fizzbuzz")
266+
}
267+
}

0 commit comments

Comments
 (0)