Skip to content

Commit d70d76e

Browse files
author
Dean Karn
authored
Improvements (#30)
NOTE: breaking change as now relying on go-playground/pkg/runtime for stack information previously within go-playground/errors Added default logger. If you register your own logger, of any kind, the default logger is removed and so is backward compatible. It is only registered when attached to a terminal. Added Close methods to handlers to allow resource cleanup & automatic removal of the logger now that RemoveHandler and AddHandler can be made on the fly. Updated to use go-playground/pkg/runtime.StackLevel(...) previously found int go-playground/errors
1 parent fdcdf50 commit d70d76e

File tree

24 files changed

+983
-173
lines changed

24 files changed

+983
-173
lines changed

.travis.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: go
2+
go:
3+
- 1.12.5
4+
- tip
5+
matrix:
6+
allow_failures:
7+
- go: tip
8+
9+
notifications:
10+
email:
11+
recipients: [email protected]
12+
on_success: change
13+
on_failure: always
14+
15+
before_install:
16+
- go get -u github.com/go-playground/overalls
17+
- go get -u github.com/mattn/goveralls
18+
19+
script:
20+
- make test
21+
- go vet ./...
22+
23+
after_success: |
24+
[ $TRAVIS_GO_VERSION = 1.12.5 ] &&
25+
overalls -project="github.com/go-playground/log" -covermode=count -ignore=.git,examples -debug &&
26+
goveralls -coverprofile=overalls.coverprofile -service travis-ci -repotoken $COVERALLS_TOKEN

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## log
2-
<img align="right" src="https://raw.githubusercontent.com/go-playground/log/master/logo.png">![Project status](https://img.shields.io/badge/version-6.4.0-green.svg)
3-
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/log/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/log)
2+
<img align="right" src="https://raw.githubusercontent.com/go-playground/log/master/logo.png">![Project status](https://img.shields.io/badge/version-7.0.0-green.svg)
3+
[![Build Status](https://travis-ci.org/go-playground/log.svg?branch=master)](https://travis-ci.org/go-playground/log)
44
[![Coverage Status](https://coveralls.io/repos/github/go-playground/log/badge.svg?branch=master)](https://coveralls.io/github/go-playground/log?branch=master)
55
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/log)](https://goreportcard.com/report/github.com/go-playground/log)
66
[![GoDoc](https://godoc.org/github.com/go-playground/log?status.svg)](https://godoc.org/github.com/go-playground/log)
@@ -18,7 +18,8 @@ Features
1818
- [x] Logger is simple, only logic to create the log entry and send it off to the handlers and they take it from there.
1919
- [x] Ability to specify which log levels get sent to each handler
2020
- [x] Built-in console, syslog, http, HipChat, json and email handlers
21-
- [x] Handlers are simple to write + easy to register
21+
- [x] Handlers are simple to write + easy to register + easy to remove
22+
- [x] Default logger for quick prototyping and cli applications. It is automatically removed when you register one of your own.
2223
- [x] Logger is a singleton ( one of the few instances a singleton is desired ) so the root package registers which handlers are used and any libraries just follow suit.
2324
- [x] Convenient context helpers `GetContext` & `SetContext`
2425
- [x] Works with go-playground/errors extracting types and tags when used with `WithError`, is the default
@@ -36,7 +37,7 @@ go get -u github.com/go-playground/log
3637

3738
Usage
3839
------
39-
import the log package, setup at least one handler
40+
import the log package, it is recommended to set up at least one handler, but there is a default console logger.
4041
```go
4142
package main
4243

@@ -48,6 +49,8 @@ import (
4849
)
4950

5051
func main() {
52+
// There is a default logger with the same settings
53+
// once any other logger is registered the default logger is removed.
5154
cLog := console.New(true)
5255
log.AddHandler(cLog, log.AllLevels...)
5356

_examples/basic/main.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
package main
22

33
import (
4-
"errors"
5-
4+
"github.com/go-playground/errors"
65
"github.com/go-playground/log"
7-
"github.com/go-playground/log/handlers/console"
86
)
97

108
func main() {
11-
cLog := console.New(true)
12-
log.AddHandler(cLog, log.AllLevels...)
13-
149
// Trace
1510
defer log.WithTrace().Info("time to run")
1611

_examples/handler/main.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"github.com/go-playground/errors"
5+
6+
"github.com/go-playground/log"
7+
"github.com/go-playground/log/handlers/console"
8+
)
9+
10+
func main() {
11+
cLog := console.New(true)
12+
log.AddHandler(cLog, log.AllLevels...)
13+
14+
// Trace
15+
defer log.WithTrace().Info("time to run")
16+
17+
log.Debug("debug")
18+
log.Info("info")
19+
log.Notice("notice")
20+
log.Warn("warn")
21+
log.Error("error")
22+
// log.Panic("panic") // this will panic
23+
log.Alert("alert")
24+
// log.Fatal("fatal") // this will call os.Exit(1)
25+
26+
err := errors.New("the is an error")
27+
// logging with fields can be used with any of the above
28+
log.WithError(err).WithFields(log.F("key", "value")).Info("test info")
29+
30+
// predefined global fields
31+
log.WithDefaultFields(log.Fields{
32+
{"program", "test"},
33+
{"version", "0.1.3"},
34+
}...)
35+
36+
log.WithField("key", "value").Info("testing default fields")
37+
38+
// or request scoped default fields
39+
logger := log.WithFields(
40+
log.F("request", "req"),
41+
log.F("scoped", "sco"),
42+
)
43+
44+
logger.WithField("key", "value").Info("test")
45+
}

byte_pool.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package log
2+
3+
import "sync"
4+
5+
// BytePool represents a reusable byte pool. It is a centralized global instance for this package and can be accessed by
6+
// calling log.BytePool(). It is intended to be used by Handlers.
7+
type ByteArrayPool struct {
8+
pool *sync.Pool
9+
}
10+
11+
func (p *ByteArrayPool) Get() []byte {
12+
return p.pool.Get().([]byte)
13+
}
14+
15+
func (p *ByteArrayPool) Put(b []byte) {
16+
p.pool.Put(b[:0])
17+
}

default_logger.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package log
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io"
7+
stdlog "log"
8+
"os"
9+
"strconv"
10+
11+
"github.com/go-playground/ansi"
12+
)
13+
14+
const (
15+
space = byte(' ')
16+
equals = byte('=')
17+
newLine = byte('\n')
18+
base10 = 10
19+
v = "%v"
20+
)
21+
22+
var (
23+
defaultLoggerWriter io.Writer = os.Stderr // here for tests only
24+
defaultLoggerTimeFormat = "2006-01-02 15:04:05.000000000Z07:00" // here for tests only
25+
)
26+
27+
// console is an instance of the console logger
28+
type console struct {
29+
colors [8]ansi.EscSeq
30+
writer io.Writer
31+
timestampFormat string
32+
r *io.PipeReader
33+
}
34+
35+
func newDefaultLogger() *console {
36+
c := &console{
37+
colors: [...]ansi.EscSeq{
38+
DebugLevel: ansi.Green,
39+
InfoLevel: ansi.Blue,
40+
NoticeLevel: ansi.LightCyan,
41+
WarnLevel: ansi.LightYellow,
42+
ErrorLevel: ansi.LightRed,
43+
PanicLevel: ansi.Red,
44+
AlertLevel: ansi.Red + ansi.Underline,
45+
FatalLevel: ansi.Red + ansi.Underline + ansi.Blink,
46+
},
47+
writer: defaultLoggerWriter,
48+
timestampFormat: defaultLoggerTimeFormat,
49+
}
50+
done := make(chan struct{})
51+
go c.handleStdLogger(done)
52+
<-done // have to wait, it was running too quickly and some messages can be lost
53+
return c
54+
}
55+
56+
// this will redirect the output of
57+
func (c *console) handleStdLogger(done chan<- struct{}) {
58+
var w *io.PipeWriter
59+
c.r, w = io.Pipe()
60+
stdlog.SetOutput(w)
61+
62+
scanner := bufio.NewScanner(c.r)
63+
go func() {
64+
done <- struct{}{}
65+
}()
66+
67+
for scanner.Scan() {
68+
WithField("stdlog", true).Info(scanner.Text())
69+
}
70+
_ = c.r.Close()
71+
_ = w.Close()
72+
}
73+
74+
// Log handles the log entry
75+
func (c *console) Log(e Entry) {
76+
var i int
77+
78+
b := BytePool().Get()
79+
lvl := e.Level.String()
80+
color := c.colors[e.Level]
81+
b = append(b, e.Timestamp.Format(c.timestampFormat)...)
82+
b = append(b, space)
83+
b = append(b, color...)
84+
85+
for i = 0; i < 6-len(lvl); i++ {
86+
b = append(b, space)
87+
}
88+
b = append(b, lvl...)
89+
b = append(b, ansi.Reset...)
90+
b = append(b, space)
91+
b = append(b, e.Message...)
92+
93+
for _, f := range e.Fields {
94+
b = append(b, space)
95+
b = append(b, color...)
96+
b = append(b, f.Key...)
97+
b = append(b, ansi.Reset...)
98+
b = append(b, equals)
99+
100+
switch t := f.Value.(type) {
101+
case string:
102+
b = append(b, t...)
103+
case int:
104+
b = strconv.AppendInt(b, int64(t), base10)
105+
case int8:
106+
b = strconv.AppendInt(b, int64(t), base10)
107+
case int16:
108+
b = strconv.AppendInt(b, int64(t), base10)
109+
case int32:
110+
b = strconv.AppendInt(b, int64(t), base10)
111+
case int64:
112+
b = strconv.AppendInt(b, t, base10)
113+
case uint:
114+
b = strconv.AppendUint(b, uint64(t), base10)
115+
case uint8:
116+
b = strconv.AppendUint(b, uint64(t), base10)
117+
case uint16:
118+
b = strconv.AppendUint(b, uint64(t), base10)
119+
case uint32:
120+
b = strconv.AppendUint(b, uint64(t), base10)
121+
case uint64:
122+
b = strconv.AppendUint(b, t, base10)
123+
case float32:
124+
b = strconv.AppendFloat(b, float64(t), 'f', -1, 32)
125+
case float64:
126+
b = strconv.AppendFloat(b, t, 'f', -1, 64)
127+
case bool:
128+
b = strconv.AppendBool(b, t)
129+
default:
130+
b = append(b, fmt.Sprintf(v, f.Value)...)
131+
}
132+
}
133+
b = append(b, newLine)
134+
_, _ = c.writer.Write(b)
135+
BytePool().Put(b)
136+
}
137+
138+
// Close cleans up any resources
139+
func (c *console) Close() error {
140+
// reset the output back to original
141+
stdlog.SetOutput(os.Stderr)
142+
// since we reset the output piror to closing we don't have to wait
143+
if c.r != nil {
144+
_ = c.r.Close()
145+
}
146+
return nil
147+
}

0 commit comments

Comments
 (0)