mirror of
https://github.com/golang/go
synced 2024-11-24 10:20:01 -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"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,11 +51,12 @@ const (
|
|||||||
// the Writer's Write method. A Logger can be used simultaneously from
|
// the Writer's Write method. A Logger can be used simultaneously from
|
||||||
// multiple goroutines; it guarantees to serialize access to the Writer.
|
// multiple goroutines; it guarantees to serialize access to the Writer.
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
mu sync.Mutex // ensures atomic writes; protects the following fields
|
mu sync.Mutex // ensures atomic writes; protects the following fields
|
||||||
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
|
prefix string // prefix on each line to identify the logger (but see Lmsgprefix)
|
||||||
flag int // properties
|
flag int // properties
|
||||||
out io.Writer // destination for output
|
out io.Writer // destination for output
|
||||||
buf []byte // for accumulating text to write
|
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
|
// 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.
|
// after the log header if the Lmsgprefix flag is provided.
|
||||||
// The flag argument defines the logging properties.
|
// The flag argument defines the logging properties.
|
||||||
func New(out io.Writer, prefix string, flag int) *Logger {
|
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.
|
// SetOutput sets the output destination for the logger.
|
||||||
@ -71,6 +77,11 @@ func (l *Logger) SetOutput(w io.Writer) {
|
|||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
defer l.mu.Unlock()
|
||||||
l.out = w
|
l.out = w
|
||||||
|
isDiscard := int32(0)
|
||||||
|
if w == io.Discard {
|
||||||
|
isDiscard = 1
|
||||||
|
}
|
||||||
|
atomic.StoreInt32(&l.isDiscard, isDiscard)
|
||||||
}
|
}
|
||||||
|
|
||||||
var std = New(os.Stderr, "", LstdFlags)
|
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.
|
// Printf calls l.Output to print to the logger.
|
||||||
// Arguments are handled in the manner of fmt.Printf.
|
// Arguments are handled in the manner of fmt.Printf.
|
||||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||||
|
if atomic.LoadInt32(&l.isDiscard) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
l.Output(2, fmt.Sprintf(format, v...))
|
l.Output(2, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print calls l.Output to print to the logger.
|
// Print calls l.Output to print to the logger.
|
||||||
// Arguments are handled in the manner of fmt.Print.
|
// 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.
|
// Println calls l.Output to print to the logger.
|
||||||
// Arguments are handled in the manner of fmt.Println.
|
// 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).
|
// Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
|
||||||
func (l *Logger) Fatal(v ...interface{}) {
|
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.
|
// SetOutput sets the output destination for the standard logger.
|
||||||
func SetOutput(w io.Writer) {
|
func SetOutput(w io.Writer) {
|
||||||
std.mu.Lock()
|
std.SetOutput(w)
|
||||||
defer std.mu.Unlock()
|
|
||||||
std.out = w
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flags returns the output flags for the standard logger.
|
// 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.
|
// Print calls Output to print to the standard logger.
|
||||||
// Arguments are handled in the manner of fmt.Print.
|
// Arguments are handled in the manner of fmt.Print.
|
||||||
func Print(v ...interface{}) {
|
func Print(v ...interface{}) {
|
||||||
|
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
std.Output(2, fmt.Sprint(v...))
|
std.Output(2, fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Printf calls Output to print to the standard logger.
|
// Printf calls Output to print to the standard logger.
|
||||||
// Arguments are handled in the manner of fmt.Printf.
|
// Arguments are handled in the manner of fmt.Printf.
|
||||||
func Printf(format string, v ...interface{}) {
|
func Printf(format string, v ...interface{}) {
|
||||||
|
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
std.Output(2, fmt.Sprintf(format, v...))
|
std.Output(2, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Println calls Output to print to the standard logger.
|
// Println calls Output to print to the standard logger.
|
||||||
// Arguments are handled in the manner of fmt.Println.
|
// Arguments are handled in the manner of fmt.Println.
|
||||||
func Println(v ...interface{}) {
|
func Println(v ...interface{}) {
|
||||||
|
if atomic.LoadInt32(&std.isDiscard) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
std.Output(2, fmt.Sprintln(v...))
|
std.Output(2, fmt.Sprintln(v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ package log
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@ -20,7 +21,7 @@ const (
|
|||||||
Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
|
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]`
|
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]`
|
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
|
Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
|
||||||
Rshortfile = `[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) {
|
func BenchmarkItoa(b *testing.B) {
|
||||||
dst := make([]byte, 0, 64)
|
dst := make([]byte, 0, 64)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
Loading…
Reference in New Issue
Block a user