mirror of
https://github.com/golang/go
synced 2024-11-24 06:20:02 -07:00
log: don't format if writing to io.Discard
Fixes #47164 Change-Id: Ied03842360be4c86f1d9ead816f12c057a1f8dad Reviewed-on: https://go-review.googlesource.com/c/go/+/348741 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Valentin Deleplace <deleplace@google.com>
This commit is contained in:
parent
7f36ef0aff
commit
323c6f74d3
@ -20,6 +20,7 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -55,6 +56,7 @@ type Logger struct {
|
||||
flag int // properties
|
||||
out io.Writer // destination for output
|
||||
buf []byte // for accumulating text to write
|
||||
isDiscard int32 // atomic boolean: whether out == io.Discard
|
||||
}
|
||||
|
||||
// New creates a new Logger. The out variable sets the
|
||||
@ -63,7 +65,11 @@ type Logger struct {
|
||||
// after the log header if the Lmsgprefix flag is provided.
|
||||
// The flag argument defines the logging properties.
|
||||
func New(out io.Writer, prefix string, flag int) *Logger {
|
||||
return &Logger{out: out, prefix: prefix, flag: flag}
|
||||
l := &Logger{out: out, prefix: prefix, flag: flag}
|
||||
if out == io.Discard {
|
||||
l.isDiscard = 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// SetOutput sets the output destination for the logger.
|
||||
@ -71,6 +77,11 @@ func (l *Logger) SetOutput(w io.Writer) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.out = w
|
||||
isDiscard := int32(0)
|
||||
if w == io.Discard {
|
||||
isDiscard = 1
|
||||
}
|
||||
atomic.StoreInt32(&l.isDiscard, isDiscard)
|
||||
}
|
||||
|
||||
var std = New(os.Stderr, "", LstdFlags)
|
||||
@ -188,16 +199,29 @@ func (l *Logger) Output(calldepth int, s string) error {
|
||||
// Printf calls l.Output to print to the logger.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||
if atomic.LoadInt32(&l.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
l.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Print calls l.Output to print to the logger.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
|
||||
func (l *Logger) Print(v ...interface{}) {
|
||||
if atomic.LoadInt32(&l.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
l.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Println calls l.Output to print to the logger.
|
||||
// Arguments are handled in the manner of fmt.Println.
|
||||
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
|
||||
func (l *Logger) Println(v ...interface{}) {
|
||||
if atomic.LoadInt32(&l.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
l.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
|
||||
func (l *Logger) Fatal(v ...interface{}) {
|
||||
@ -277,9 +301,7 @@ func (l *Logger) Writer() io.Writer {
|
||||
|
||||
// SetOutput sets the output destination for the standard logger.
|
||||
func SetOutput(w io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.out = w
|
||||
std.SetOutput(w)
|
||||
}
|
||||
|
||||
// Flags returns the output flags for the standard logger.
|
||||
@ -314,18 +336,27 @@ func Writer() io.Writer {
|
||||
// Print calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Print.
|
||||
func Print(v ...interface{}) {
|
||||
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
std.Output(2, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Printf calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Printf.
|
||||
func Printf(format string, v ...interface{}) {
|
||||
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
std.Output(2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Println calls Output to print to the standard logger.
|
||||
// Arguments are handled in the manner of fmt.Println.
|
||||
func Println(v ...interface{}) {
|
||||
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||
return
|
||||
}
|
||||
std.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ package log
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -20,7 +21,7 @@ const (
|
||||
Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
|
||||
Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
|
||||
Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
|
||||
Rline = `(60|62):` // must update if the calls to l.Printf / l.Print below move
|
||||
Rline = `(61|63):` // must update if the calls to l.Printf / l.Print below move
|
||||
Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
|
||||
Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline
|
||||
)
|
||||
@ -179,6 +180,17 @@ func TestEmptyPrintCreatesLine(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscard(t *testing.T) {
|
||||
l := New(io.Discard, "", 0)
|
||||
s := strings.Repeat("a", 102400)
|
||||
c := testing.AllocsPerRun(100, func() { l.Printf("%s", s) })
|
||||
// One allocation for slice passed to Printf,
|
||||
// but none for formatting of long string.
|
||||
if c > 1 {
|
||||
t.Errorf("got %v allocs, want at most 1", c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItoa(b *testing.B) {
|
||||
dst := make([]byte, 0, 64)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
Loading…
Reference in New Issue
Block a user