Skip to content

Commit d55926d

Browse files
author
Dean Karn
authored
V8.0.0 rc7 (#45)
- Removed ability to remove individual log levels. Can use AddHandler and RemoveHandler to accomplish the same. Will leave it this way unless there's a compelling reason to expose this functionality. - Move std log redirect to top level our of console handler. - Add error and warning checks for std log output - fix std log redirect reset
1 parent 77e35e4 commit d55926d

File tree

6 files changed

+71
-68
lines changed

6 files changed

+71
-68
lines changed

_examples/basic/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package main
22

33
import (
44
"io"
5+
stdlog "log"
56

67
"github.com/go-playground/errors/v5"
78
"github.com/go-playground/log/v8"
89
)
910

1011
func main() {
12+
log.RedirectGoStdLog(true)
13+
1114
// Trace
1215
defer log.WithTrace().Info("time to run")
1316

@@ -44,4 +47,8 @@ func main() {
4447
)
4548

4649
logger.WithField("key", "value").Info("test")
50+
51+
stdlog.Println("This was redirected from Go STD output!")
52+
log.RedirectGoStdLog(false)
53+
stdlog.Println("This was NOT redirected from Go STD output!")
4754
}

benchmarks/benchmark_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var _jane = user{
3030
// annoying because you have to manipulate the TestMain before
3131
// running the benchmark you want.
3232
func TestMain(m *testing.M) {
33-
cLog := log.NewConsoleBuilder().WithGoSTDErrLogs(false).WithWriter(ioutil.Discard).Build()
33+
cLog := log.NewConsoleBuilder().WithWriter(ioutil.Discard).Build()
3434
log.AddHandler(cLog, log.AllLevels...)
3535
os.Exit(m.Run())
3636
}

default_logger.go

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package log
22

33
import (
4-
"bufio"
54
"fmt"
65
"io"
7-
stdlog "log"
86
"os"
97
"strconv"
108
"sync"
@@ -22,23 +20,16 @@ const (
2220
type ConsoleBuilder struct {
2321
writer io.Writer
2422
timestampFormat string
25-
redirect bool
2623
}
2724

2825
// NewConsoleBuilder creates a new ConsoleBuilder for configuring and creating a new console logger
2926
func NewConsoleBuilder() *ConsoleBuilder {
3027
return &ConsoleBuilder{
3128
writer: os.Stderr,
3229
timestampFormat: DefaultTimeFormat,
33-
redirect: true,
3430
}
3531
}
3632

37-
func (b *ConsoleBuilder) WithGoSTDErrLogs(redirect bool) *ConsoleBuilder {
38-
b.redirect = redirect
39-
return b
40-
}
41-
4233
func (b *ConsoleBuilder) WithWriter(writer io.Writer) *ConsoleBuilder {
4334
b.writer = writer
4435
return b
@@ -50,44 +41,19 @@ func (b *ConsoleBuilder) WithTimestampFormat(format string) *ConsoleBuilder {
5041
}
5142

5243
func (b *ConsoleBuilder) Build() *Logger {
53-
c := &Logger{
44+
return &Logger{
5445
writer: b.writer,
5546
timestampFormat: b.timestampFormat,
5647
}
57-
if b.redirect {
58-
ready := make(chan struct{})
59-
go c.handleStdLogger(ready)
60-
<-ready // have to wait, it was running too quickly and some messages can be lost
61-
}
62-
return c
6348
}
6449

6550
// Logger is an instance of the console logger
6651
type Logger struct {
6752
m sync.Mutex
6853
writer io.Writer
69-
r *io.PipeReader
7054
timestampFormat string
7155
}
7256

73-
// this will redirect the output of
74-
func (c *Logger) handleStdLogger(ready chan<- struct{}) {
75-
var w *io.PipeWriter
76-
c.r, w = io.Pipe()
77-
stdlog.SetOutput(w)
78-
79-
scanner := bufio.NewScanner(c.r)
80-
go func() {
81-
close(ready)
82-
}()
83-
84-
for scanner.Scan() {
85-
WithField("stdlog", true).Notice(scanner.Text())
86-
}
87-
_ = c.r.Close()
88-
_ = w.Close()
89-
}
90-
9157
// Log handles the log entry
9258
func (c *Logger) Log(e Entry) {
9359
var lvl string
@@ -152,26 +118,3 @@ func (c *Logger) Log(e Entry) {
152118

153119
BytePool().Put(buff)
154120
}
155-
156-
// Close cleans up any resources and de-registers the handler with the logger
157-
func (c *Logger) Close() error {
158-
RemoveHandler(c)
159-
// reset the output back to original
160-
// since we reset the output prior to closing we don't have to wait
161-
stdlog.SetOutput(os.Stderr)
162-
if c.r != nil {
163-
_ = c.r.Close()
164-
}
165-
return nil
166-
}
167-
168-
func (c *Logger) closeAlreadyLocked() error {
169-
removeHandler(c)
170-
// reset the output back to original
171-
// since we reset the output prior to closing we don't have to wait
172-
stdlog.SetOutput(os.Stderr)
173-
if c.r != nil {
174-
_ = c.r.Close()
175-
}
176-
return nil
177-
}

default_logger_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ func TestConsoleLogger(t *testing.T) {
2727

2828
cLog := NewConsoleBuilder().WithWriter(buff).WithTimestampFormat("").Build()
2929
AddHandler(cLog, AllLevels...)
30-
defer func() { _ = cLog.Close() }()
3130
for i, tt := range tests {
3231

3332
buff.Reset()
@@ -90,6 +89,7 @@ func TestConsoleLogger(t *testing.T) {
9089

9190
func TestConsoleSTDLogCapturing(t *testing.T) {
9291
buff := new(buffer)
92+
RedirectGoStdLog(true)
9393
cLog := NewConsoleBuilder().WithWriter(buff).WithTimestampFormat("MST").Build()
9494
AddHandler(cLog, AllLevels...)
9595

log.go

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package log
22

33
import (
4+
"bufio"
45
"context"
6+
"io"
7+
stdlog "log"
58
"os"
9+
"strings"
610
"sync"
711
"time"
812

@@ -44,7 +48,9 @@ var (
4448
}{
4549
name: "log",
4650
}
47-
rw sync.RWMutex
51+
rw sync.RWMutex
52+
stdLogWriter *io.PipeWriter
53+
redirectComplete chan struct{}
4854
)
4955

5056
// Field is a single Field key and value
@@ -53,6 +59,54 @@ type Field struct {
5359
Value interface{} `json:"value"`
5460
}
5561

62+
// RedirectGoStdLog is used to redirect Go's internal std log output to this logger.
63+
func RedirectGoStdLog(redirect bool) {
64+
if (redirect && stdLogWriter != nil) || (!redirect && stdLogWriter == nil) {
65+
// already redirected or already not redirected
66+
return
67+
}
68+
if !redirect {
69+
stdlog.SetOutput(os.Stderr)
70+
// will stop scanner reading PipeReader
71+
_ = stdLogWriter.Close()
72+
stdLogWriter = nil
73+
<-redirectComplete
74+
return
75+
}
76+
77+
ready := make(chan struct{})
78+
redirectComplete = make(chan struct{})
79+
80+
// last option is to redirect
81+
go func() {
82+
var r *io.PipeReader
83+
r, stdLogWriter = io.Pipe()
84+
defer func() {
85+
_ = r.Close()
86+
}()
87+
88+
stdlog.SetOutput(stdLogWriter)
89+
defer func() {
90+
close(redirectComplete)
91+
redirectComplete = nil
92+
}()
93+
94+
scanner := bufio.NewScanner(r)
95+
close(ready)
96+
for scanner.Scan() {
97+
txt := scanner.Text()
98+
if strings.Contains(txt, "error") {
99+
WithField("stdlog", true).Error(txt)
100+
} else if strings.Contains(txt, "warning") {
101+
WithField("stdlog", true).Warn(txt)
102+
} else {
103+
WithField("stdlog", true).Notice(txt)
104+
}
105+
}
106+
}()
107+
<-ready
108+
}
109+
56110
// SetExitFunc sets the provided function as the exit function used in Fatal(),
57111
// Fatalf(), Panic() and Panicf(). This is primarily used when wrapping this library,
58112
// you can set this to enable testing (with coverage) of your Fatal() and Fatalf()
@@ -116,7 +170,6 @@ func AddHandler(h Handler, levels ...Level) {
116170
defer rw.Unlock()
117171
if defaultHandler != nil {
118172
removeHandler(h)
119-
_ = defaultHandler.closeAlreadyLocked()
120173
defaultHandler = nil
121174
}
122175
for _, level := range levels {
@@ -149,9 +202,9 @@ OUTER:
149202
}
150203
}
151204

152-
// RemoveHandlerLevels removes the supplied levels, if no more levels exists for the handler
205+
// removeHandlerLevels removes the supplied levels, if no more levels exists for the handler
153206
// it will no longer be registered and need to added via AddHandler again.
154-
func RemoveHandlerLevels(h Handler, levels ...Level) {
207+
func removeHandlerLevels(h Handler, levels ...Level) {
155208
rw.Lock()
156209
defer rw.Unlock()
157210
OUTER:

log_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,27 +1038,27 @@ func TestRemoveHandlerLevels(t *testing.T) {
10381038
}
10391039
logHandlers = map[Level][]Handler{}
10401040
AddHandler(th, InfoLevel)
1041-
RemoveHandlerLevels(th, InfoLevel)
1041+
removeHandlerLevels(th, InfoLevel)
10421042
if len(logHandlers) != 0 {
10431043
t.Error("expected 0 handlers")
10441044
}
10451045

10461046
AddHandler(th, InfoLevel)
10471047
AddHandler(th2, InfoLevel)
1048-
RemoveHandlerLevels(th, InfoLevel)
1048+
removeHandlerLevels(th, InfoLevel)
10491049
if len(logHandlers) != 1 {
10501050
t.Error("expected 1 handlers left")
10511051
}
10521052
if len(logHandlers[InfoLevel]) != 1 {
10531053
t.Error("expected 1 handlers with InfoLevel left")
10541054
}
1055-
RemoveHandlerLevels(th2, InfoLevel)
1055+
removeHandlerLevels(th2, InfoLevel)
10561056
if len(logHandlers) != 0 {
10571057
t.Error("expected 0 handlers")
10581058
}
10591059

10601060
AddHandler(th, AllLevels...)
1061-
RemoveHandlerLevels(th, DebugLevel)
1061+
removeHandlerLevels(th, DebugLevel)
10621062
if len(logHandlers) != 7 {
10631063
t.Error("expected 7 log levels left")
10641064
}

0 commit comments

Comments
 (0)