Skip to content

Commit d49e1c0

Browse files
committed
NewStdLog, NewStdLogAt, RedirectStdLog
1 parent d255071 commit d49e1c0

File tree

7 files changed

+250
-70
lines changed

7 files changed

+250
-70
lines changed

entry.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
type Entry struct {
1818
rec *driver.Recorder
1919
log *Logger
20+
21+
addSkip int
2022
}
2123

2224
// NewEntry creates a new logging entry with a logger
@@ -35,6 +37,14 @@ func (e *Entry) SetPrefix(prefix string) *Entry {
3537
return e
3638
}
3739

40+
// AddCallerSkip increases the number of callers skipped by caller annotation.
41+
// When building wrappers around the logger Entry, supplying this function
42+
// to reporting the caller's caller information of the wrapper code.
43+
func (e *Entry) AddCallerSkip(addSkip int) *Entry {
44+
e.addSkip = addSkip
45+
return e
46+
}
47+
3848
// With creates a child logger and adds structured context to it. Fields added
3949
// to the child don't affect the parent, and vice versa.
4050
func (e *Entry) With(args ...interface{}) *Entry {
@@ -73,7 +83,7 @@ func (e *Entry) Log(calldepth int, level int, arg0 interface{}, args ...interfac
7383

7484
if l.caller {
7585
// Determine caller func - it's expensive.
76-
_, r.Source, r.Line, _ = runtime.Caller(calldepth)
86+
_, r.Source, r.Line, _ = runtime.Caller(calldepth + e.addSkip)
7787
} else {
7888
r.Source, r.Line = "", 0
7989
}

global.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (C) 2017, ccpaging <[email protected]>. All rights reserved.
2+
3+
package nxlog4go
4+
5+
import (
6+
"errors"
7+
8+
"github.com/ccpaging/nxlog4go/driver"
9+
)
10+
11+
// GetLogger returns the default logger.
12+
func GetLogger() *Logger {
13+
return std
14+
}
15+
16+
// Finest is a wrapper for (*Logger).Finest
17+
func Finest(arg0 interface{}, args ...interface{}) {
18+
std.Log(2, FINEST, arg0, args...)
19+
}
20+
21+
// Fine is a wrapper for (*Logger).Fine
22+
func Fine(arg0 interface{}, args ...interface{}) {
23+
std.Log(2, FINE, arg0, args...)
24+
}
25+
26+
// Debug is a wrapper for (*Logger).Debug
27+
func Debug(arg0 interface{}, args ...interface{}) {
28+
std.Log(2, DEBUG, arg0, args...)
29+
}
30+
31+
// Trace is a wrapper for (*Logger).Trace
32+
func Trace(arg0 interface{}, args ...interface{}) {
33+
std.Log(2, TRACE, arg0, args...)
34+
}
35+
36+
// Info is a wrapper for (*Logger).Info
37+
func Info(arg0 interface{}, args ...interface{}) {
38+
std.Log(2, INFO, arg0, args...)
39+
}
40+
41+
// Warn is a wrapper for (*Logger).Warn
42+
func Warn(arg0 interface{}, args ...interface{}) error {
43+
msg := driver.ArgsToString(arg0, args...)
44+
std.Log(2, WARN, msg)
45+
return errors.New(msg)
46+
}
47+
48+
// Error is a wrapper for (*Logger).Error
49+
func Error(arg0 interface{}, args ...interface{}) error {
50+
msg := driver.ArgsToString(arg0, args...)
51+
std.Log(2, ERROR, msg)
52+
return errors.New(msg)
53+
}
54+
55+
// Critical is a wrapper for (*Logger).Critical
56+
func Critical(arg0 interface{}, args ...interface{}) error {
57+
msg := driver.ArgsToString(arg0, args...)
58+
std.Log(2, CRITICAL, msg)
59+
return errors.New(msg)
60+
}

global_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (C) 2017, ccpaging <[email protected]>. All rights reserved.
2+
3+
package nxlog4go
4+
5+
import (
6+
"bytes"
7+
"testing"
8+
)
9+
10+
func TestGloablLogger(t *testing.T) {
11+
buf := new(bytes.Buffer)
12+
13+
global := GetLogger().SetOutput(buf).SetOptions(
14+
"level", WARN,
15+
"caller", true,
16+
"format", "[%L] (%S) %M")
17+
if global == nil {
18+
t.Fatalf("GetLogger() should never return nil")
19+
}
20+
if global.stdf.level != WARN {
21+
t.Fatalf("GetLogger() produced invalid logger (incorrect level)")
22+
}
23+
24+
//func (l *Logger) Warn(args ...interface{}) error {}
25+
if err := Warn("%s %d %#v", "Warn:", 1, []int{}); err.Error() != "Warn: 1 []int{}" {
26+
t.Errorf("Warn returned invalid error: %s", err)
27+
}
28+
want := "[WARN] (nxlog4go/global_test.go) Warn: 1 []int{}\n"
29+
if got := buf.String(); got != want {
30+
t.Errorf(" got %q", got)
31+
t.Errorf(" want %q", want)
32+
}
33+
buf.Reset()
34+
35+
//func (l *Logger) Error(args ...interface{}) error {}
36+
if err := Error("%s %d %#v", "Error:", 10, []string{}); err.Error() != "Error: 10 []string{}" {
37+
t.Errorf("Error returned invalid error: %s", err)
38+
}
39+
want = "[EROR] (nxlog4go/global_test.go) Error: 10 []string{}\n"
40+
if got := buf.String(); got != want {
41+
t.Errorf(" got %q", got)
42+
t.Errorf(" want %q", want)
43+
}
44+
buf.Reset()
45+
46+
//func (l *Logger) Critical(args ...interface{}) error {}
47+
if err := Critical("%s %d %#v", "Critical:", 100, []int64{}); err.Error() != "Critical: 100 []int64{}" {
48+
t.Errorf("Critical returned invalid error: %s", err)
49+
}
50+
want = "[CRIT] (nxlog4go/global_test.go) Critical: 100 []int64{}\n"
51+
if got := buf.String(); got != want {
52+
t.Errorf(" got %q", got)
53+
t.Errorf(" want %q", want)
54+
}
55+
}

nxlog4go.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const (
103103
type Logger struct {
104104
mu *sync.Mutex // ensures atomic writes; protects the following fields
105105
prefix string // prefix to write at beginning of each line
106-
caller bool // runtime caller skip
106+
caller bool // enable or disable calling runtime.Caller(...)
107107
stdf *stdFilter
108108
filters map[string]*driver.Filter // a collection of Filter
109109
}

nxlog4go_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ func BenchmarkFileWriter(b *testing.B) {
319319
w.Close()
320320
os.Remove(benchLogFile)
321321
}()
322-
b.StopTimer()
323322

324323
sl := NewLogger(INFO).SetOutput(w).SetOptions("format", testBenchFormat, "caller", false)
325324

@@ -339,8 +338,6 @@ func BenchmarkFileUtilWriter(b *testing.B) {
339338
w.Close()
340339
os.Remove(benchLogFile)
341340
}()
342-
defer w.Close()
343-
b.StopTimer()
344341

345342
sl := NewLogger(INFO).SetOutput(w).SetOptions("format", testBenchFormat, "caller", false)
346343

@@ -357,7 +354,6 @@ func BenchmarkFileBufWriter(b *testing.B) {
357354
w.Close()
358355
os.Remove(benchLogFile)
359356
}()
360-
b.StopTimer()
361357

362358
sl := NewLogger(INFO).SetOutput(w).SetOptions("format", testBenchFormat, "caller", false)
363359

stdlog.go

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,93 @@
1+
// Copyright (c) 2016 Uber Technologies, Inc.
12
// Copyright (C) 2017, ccpaging <[email protected]>. All rights reserved.
23

34
package nxlog4go
45

56
import (
6-
"errors"
7-
8-
"github.com/ccpaging/nxlog4go/driver"
7+
"bytes"
8+
"log"
99
)
1010

11-
// GetLogger returns the default logger.
12-
func GetLogger() *Logger {
13-
return std
14-
}
15-
16-
// Finest is a wrapper for (*Logger).Finest
17-
func Finest(arg0 interface{}, args ...interface{}) {
18-
std.Log(2, FINEST, arg0, args...)
11+
// NewStdLog returns a *log.Logger which writes to the supplied logger Entry at
12+
// Info Level.
13+
func NewStdLog(e *Entry) *log.Logger {
14+
logFunc := e.Info
15+
return log.New(&logWriter{logFunc}, "" /* prefix */, 0 /* flags */)
1916
}
2017

21-
// Fine is a wrapper for (*Logger).Fine
22-
func Fine(arg0 interface{}, args ...interface{}) {
23-
std.Log(2, FINE, arg0, args...)
18+
// NewStdLogAt returns *log.Logger which writes to supplied logger Entry at
19+
// required level.
20+
func NewStdLogAt(e *Entry, level interface{}) *log.Logger {
21+
logFunc := levelToFunc(e, level)
22+
return log.New(&logWriter{logFunc}, "" /* prefix */, 0 /* flags */)
2423
}
2524

26-
// Debug is a wrapper for (*Logger).Debug
27-
func Debug(arg0 interface{}, args ...interface{}) {
28-
std.Log(2, DEBUG, arg0, args...)
25+
// RedirectStdLog redirects output from the standard library's package-global
26+
// logger to the supplied logger at InfoLevel. Since zap already handles caller
27+
// annotations, timestamps, etc., it automatically disables the standard
28+
// library's annotations and prefixing.
29+
//
30+
// It returns a function to restore the original prefix and flags and reset the
31+
// standard library's output to os.Stderr.
32+
func RedirectStdLog(e *Entry) func() {
33+
return redirectStdLogAt(e, INFO)
2934
}
3035

31-
// Trace is a wrapper for (*Logger).Trace
32-
func Trace(arg0 interface{}, args ...interface{}) {
33-
std.Log(2, TRACE, arg0, args...)
36+
// RedirectStdLogAt redirects output from the standard library's package-global
37+
// logger to the supplied logger at the specified level. Since zap already
38+
// handles caller annotations, timestamps, etc., it automatically disables the
39+
// standard library's annotations and prefixing.
40+
//
41+
// It returns a function to restore the original prefix and flags and reset the
42+
// standard library's output to os.Stderr.
43+
func RedirectStdLogAt(e *Entry, level interface{}) func() {
44+
return redirectStdLogAt(e, level)
3445
}
3546

36-
// Info is a wrapper for (*Logger).Info
37-
func Info(arg0 interface{}, args ...interface{}) {
38-
std.Log(2, INFO, arg0, args...)
47+
func redirectStdLogAt(e *Entry, level interface{}) func() {
48+
flags := log.Flags()
49+
prefix := log.Prefix()
50+
writer := log.Writer()
51+
log.SetFlags(0)
52+
log.SetPrefix("")
53+
logFunc := levelToFunc(e.AddCallerSkip(3), level)
54+
log.SetOutput(&logWriter{logFunc})
55+
return func() {
56+
log.SetFlags(flags)
57+
log.SetPrefix(prefix)
58+
log.SetOutput(writer)
59+
}
3960
}
4061

41-
// Warn is a wrapper for (*Logger).Warn
42-
func Warn(arg0 interface{}, args ...interface{}) error {
43-
msg := driver.ArgsToString(arg0, args...)
44-
std.Log(2, WARN, msg)
45-
return errors.New(msg)
62+
func levelToFunc(e *Entry, level interface{}) func(interface{}, ...interface{}) {
63+
n := Level(INFO).Int(level)
64+
switch n {
65+
case FINEST:
66+
return e.Finest
67+
case FINE:
68+
return e.Fine
69+
case DEBUG:
70+
return e.Debug
71+
case TRACE:
72+
return e.Trace
73+
case INFO:
74+
return e.Info
75+
case WARN:
76+
return e.Warn
77+
case ERROR:
78+
return e.Error
79+
case CRITICAL:
80+
return e.Critical
81+
}
82+
return e.Info
4683
}
4784

48-
// Error is a wrapper for (*Logger).Error
49-
func Error(arg0 interface{}, args ...interface{}) error {
50-
msg := driver.ArgsToString(arg0, args...)
51-
std.Log(2, ERROR, msg)
52-
return errors.New(msg)
85+
type logWriter struct {
86+
logFunc func(msg interface{}, args ...interface{})
5387
}
5488

55-
// Critical is a wrapper for (*Logger).Critical
56-
func Critical(arg0 interface{}, args ...interface{}) error {
57-
msg := driver.ArgsToString(arg0, args...)
58-
std.Log(2, CRITICAL, msg)
59-
return errors.New(msg)
89+
func (l *logWriter) Write(p []byte) (int, error) {
90+
p = bytes.TrimSpace(p)
91+
l.logFunc(string(p))
92+
return len(p), nil
6093
}

0 commit comments

Comments
 (0)