1
0
mirror of https://github.com/rs/zerolog synced 2026-06-08 17:13:30 +00:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Olivier Poitrey 9f1f25d2fa pkgerrors: quick refactoring for better readibility 2019-01-02 17:07:20 -08:00
Olivier Poitrey 6d2153805b Revert change on go.mod 2019-01-02 17:02:58 -08:00
Olivier Poitrey 2988c1e444 pkgerrors: remove fmt dep 2019-01-02 13:19:14 -08:00
Olivier Poitrey adb19ff852 Merge branch 'master' into stacktrace 2019-01-02 12:11:57 -08:00
Olivier Poitrey 3786fbfa73 Add support for stack trace extration of error fields 2018-02-11 17:55:34 -08:00
32 changed files with 104 additions and 637 deletions
-2
View File
@@ -4,8 +4,6 @@ go:
- "1.8"
- "1.9"
- "1.10"
- "1.11"
- "1.12"
- "master"
matrix:
allow_failures:
+15 -19
View File
@@ -53,7 +53,7 @@ func main() {
// UNIX Time is faster and smaller than most timestamps
// If you set zerolog.TimeFieldFormat to an empty string,
// logs will write with UNIX time
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Print("hello world")
}
@@ -76,20 +76,15 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Debug().
Str("Scale", "833 cents").
Float64("Interval", 833.09).
Msg("Fibonacci is everywhere")
log.Debug().
Str("Name", "Tom").
Send()
}
// Output: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
// Output: {"level":"debug","Name":"Tom","time":1562212768}
// Output: {"time":1524104936,"level":"debug","Scale":"833 cents","Interval":833.09,"message":"Fibonacci is everywhere"}
```
> You'll note in the above example that when adding contextual fields, the fields are strongly typed. You can find the full list of supported fields [here](#standard-types)
@@ -107,7 +102,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Info().Msg("hello world")
}
@@ -125,7 +120,6 @@ func main() {
* warn (`zerolog.WarnLevel`, 2)
* info (`zerolog.InfoLevel`, 1)
* debug (`zerolog.DebugLevel`, 0)
* trace (`zerolog.TraceLevel`, -1)
You can set the Global logging level to any of these options using the `SetGlobalLevel` function in the zerolog package, passing in one of the given constants above, e.g. `zerolog.InfoLevel` would be the "info" level. Whichever level is chosen, all logs with a level greater than or equal to that level will be written. To turn off logging entirely, pass the `zerolog.Disabled` constant.
@@ -144,7 +138,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
debug := flag.Bool("debug", false, "sets log level to debug")
flag.Parse()
@@ -195,7 +189,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Log().
Str("foo", "bar").
@@ -221,7 +215,7 @@ func main() {
err := errors.New("A repo man spends his life getting into tense situations")
service := "myservice"
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Fatal().
Err(err).
@@ -480,10 +474,12 @@ Some settings can be changed and will by applied to all loggers:
* `zerolog.LevelFieldName`: Can be set to customize level field name.
* `zerolog.MessageFieldName`: Can be set to customize message field name.
* `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formated as UNIX timestamp.
* `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
* `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`).
* `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with an empty string, times are formated as UNIX timestamp.
// DurationFieldUnit defines the unit for time.Duration type fields added
// using the Dur method.
* `DurationFieldUnit`: Sets the unit of the fields added by `Dur` (default: `time.Millisecond`).
* `DurationFieldInteger`: If set to true, `Dur` fields are formatted as integers instead of floats.
* `ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
## Field Types
@@ -582,7 +578,7 @@ Log a static string, without any context or `printf`-style templating:
## Caveats
Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:
Note that zerolog does de-duplication fields. Using the same key multiple times creates multiple keys in final JSON:
```go
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
@@ -592,4 +588,4 @@ logger.Info().
// Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
```
In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.
However, its not a big deal as JSON accepts dup keys; the last one prevails.
-6
View File
@@ -85,12 +85,6 @@ func (a *Array) Hex(val []byte) *Array {
return a
}
// RawJSON adds already encoded JSON to the array.
func (a *Array) RawJSON(val []byte) *Array {
a.buf = appendJSON(enc.AppendArrayDelim(a.buf), val)
return a
}
// Err serializes and appends the err to the array.
func (a *Array) Err(err error) *Array {
marshaled := ErrorMarshalFunc(err)
+1 -2
View File
@@ -24,11 +24,10 @@ func TestArray(t *testing.T) {
Str("a").
Bytes([]byte("b")).
Hex([]byte{0x1f}).
RawJSON([]byte(`{"some":"json"}`)).
Time(time.Time{}).
IPAddr(net.IP{192, 168, 0, 10}).
Dur(0)
want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f",{"some":"json"},"0001-01-01T00:00:00Z","192.168.0.10",0]`
want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f","0001-01-01T00:00:00Z","192.168.0.10",0]`
if got := decodeObjectToStr(a.write([]byte{})); got != want {
t.Errorf("Array.write()\ngot: %s\nwant: %s", got, want)
}
+1 -1
View File
@@ -234,7 +234,7 @@ func BenchmarkLogFieldType(b *testing.B) {
func BenchmarkContextFieldType(b *testing.B) {
oldFormat := TimeFieldFormat
TimeFieldFormat = TimeFormatUnix
TimeFieldFormat = ""
defer func() { TimeFieldFormat = oldFormat }()
bools := []bool{true, false, true, false, true, false, true, false, true, false}
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
-13
View File
@@ -108,19 +108,6 @@ func ExampleLogger_Printf() {
// Output: {"level":"debug","message":"hello world"}
}
func ExampleLogger_Trace() {
dst := bytes.Buffer{}
log := New(&dst)
log.Trace().
Str("foo", "bar").
Int("n", 123).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"trace","foo":"bar","n":123,"message":"hello world"}
}
func ExampleLogger_Debug() {
dst := bytes.Buffer{}
log := New(&dst)
+10 -28
View File
@@ -13,6 +13,11 @@ import (
"time"
)
const (
colorBold = iota + 1
colorFaint
)
const (
colorBlack = iota + 30
colorRed
@@ -22,9 +27,6 @@ const (
colorMagenta
colorCyan
colorWhite
colorBold = 1
colorDarkGray = 90
)
var (
@@ -295,20 +297,9 @@ func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter {
t = ts.Format(timeFormat)
}
case json.Number:
i, err := tt.Int64()
if err != nil {
t = tt.String()
} else {
var sec, nsec int64 = i, 0
if TimeFieldFormat == TimeFormatUnixMs {
nsec = int64(time.Duration(i) * time.Millisecond)
sec = 0
}
ts := time.Unix(sec, nsec).UTC()
t = ts.Format(timeFormat)
}
t = tt.String()
}
return colorize(t, colorDarkGray, noColor)
return colorize(t, colorFaint, noColor)
}
}
@@ -317,8 +308,6 @@ func consoleDefaultFormatLevel(noColor bool) Formatter {
var l string
if ll, ok := i.(string); ok {
switch ll {
case "trace":
l = colorize("TRC", colorMagenta, noColor)
case "debug":
l = colorize("DBG", colorYellow, noColor)
case "info":
@@ -335,11 +324,7 @@ func consoleDefaultFormatLevel(noColor bool) Formatter {
l = colorize("???", colorBold, noColor)
}
} else {
if i == nil {
l = colorize("???", colorBold, noColor)
} else {
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
}
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
}
return l
}
@@ -357,22 +342,19 @@ func consoleDefaultFormatCaller(noColor bool) Formatter {
c = strings.TrimPrefix(c, cwd)
c = strings.TrimPrefix(c, "/")
}
c = colorize(c, colorBold, noColor) + colorize(" >", colorCyan, noColor)
c = colorize(c, colorBold, noColor) + colorize(" >", colorFaint, noColor)
}
return c
}
}
func consoleDefaultFormatMessage(i interface{}) string {
if i == nil {
return ""
}
return fmt.Sprintf("%s", i)
}
func consoleDefaultFormatFieldName(noColor bool) Formatter {
return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
return colorize(fmt.Sprintf("%s=", i), colorFaint, noColor)
}
}
+10 -102
View File
@@ -76,7 +76,7 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"foo"}}
_, err := w.Write([]byte(`{"foo": "DEFAULT"}`))
_, err := w.Write([]byte(`{"foo" : "DEFAULT"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
@@ -92,12 +92,12 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar"}`))
_, err := w.Write([]byte(`{"level" : "warn", "message" : "Foobar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar\n"
expectedOutput := "\x1b[2m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
@@ -109,7 +109,7 @@ func TestConsoleWriter(t *testing.T) {
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
_, err := w.Write([]byte(`{"time": "` + d + `", "level": "debug", "message": "Foobar", "foo": "bar"}`))
_, err := w.Write([]byte(`{"time" : "` + d + `", "level" : "debug", "message" : "Foobar", "foo" : "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
@@ -121,104 +121,12 @@ func TestConsoleWriter(t *testing.T) {
}
})
t.Run("Unix timestamp input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "Jan 1 00:20:34.000 DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Unix timestamp ms input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234567, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "Jan 1 00:20:34.567 DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No message field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"level": "debug", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> DBG foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No level field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> ??? Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write colorized fields", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar \x1b[36mfoo=\x1b[0mbar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write error field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "error", "message": "Foobar", "aaa": "bbb", "error": "Error"}`
evt := `{"time" : "` + d + `", "level" : "error", "message" : "Foobar", "aaa" : "bbb", "error" : "Error"}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
@@ -243,7 +151,7 @@ func TestConsoleWriter(t *testing.T) {
}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "debug", "message": "Foobar", "foo": "bar", "caller": "` + cwd + `/foo/bar.go"}`
evt := `{"time" : "` + d + `", "level" : "debug", "message" : "Foobar", "foo" : "bar", "caller" : "` + cwd + `/foo/bar.go"}`
// t.Log(evt)
_, err = w.Write([]byte(evt))
@@ -262,7 +170,7 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
evt := `{"level": "debug", "message": "Foobar", "foo": [1, 2, 3], "bar": true}`
evt := `{"level" : "debug", "message" : "Foobar", "foo" : [1, 2, 3], "bar" : true}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
@@ -284,7 +192,7 @@ func TestConsoleWriterConfiguration(t *testing.T) {
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, TimeFormat: time.RFC3339}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "info", "message": "Foobar"}`
evt := `{"time" : "` + d + `", "level" : "info", "message" : "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
@@ -302,7 +210,7 @@ func TestConsoleWriterConfiguration(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"message", "level"}}
evt := `{"level": "info", "message": "Foobar"}`
evt := `{"level" : "info", "message" : "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
@@ -320,7 +228,7 @@ func BenchmarkConsoleWriter(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
var msg = []byte(`{"level": "info", "foo": "bar", "message": "HELLO", "time": "1990-01-01"}`)
var msg = []byte(`{"level" : "info", "foo" : "bar", "message" : "HELLO", "time" : "1990-01-01"}`)
w := zerolog.ConsoleWriter{Out: ioutil.Discard, NoColor: false}
+4 -30
View File
@@ -2,7 +2,6 @@ package zerolog
import (
"io/ioutil"
"math"
"net"
"time"
)
@@ -348,31 +347,14 @@ func (c Context) Interface(key string, i interface{}) Context {
return c
}
type callerHook struct {
callerSkipFrameCount int
}
func newCallerHook(skipFrameCount int) callerHook {
return callerHook{callerSkipFrameCount: skipFrameCount}
}
type callerHook struct{}
func (ch callerHook) Run(e *Event, level Level, msg string) {
switch ch.callerSkipFrameCount {
case useGlobalSkipFrameCount:
// Extra frames to skip (added by hook infra).
e.caller(CallerSkipFrameCount + contextCallerSkipFrameCount)
default:
// Extra frames to skip (added by hook infra).
e.caller(ch.callerSkipFrameCount + contextCallerSkipFrameCount)
}
// Three extra frames to skip (added by hook infra).
e.caller(CallerSkipFrameCount + 3)
}
// useGlobalSkipFrameCount acts as a flag to informat callerHook.Run
// to use the global CallerSkipFrameCount.
const useGlobalSkipFrameCount = math.MinInt32
// ch is the default caller hook using the global CallerSkipFrameCount.
var ch = newCallerHook(useGlobalSkipFrameCount)
var ch = callerHook{}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
func (c Context) Caller() Context {
@@ -380,14 +362,6 @@ func (c Context) Caller() Context {
return c
}
// CallerWithSkipFrameCount adds the file:line of the caller with the zerolog.CallerFieldName key.
// The specified skipFrameCount int will override the global CallerSkipFrameCount for this context's respective logger.
// If set to -1 the global CallerSkipFrameCount will be used.
func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
c.l = c.l.Hook(newCallerHook(skipFrameCount))
return c
}
type stackTraceHook struct{}
func (sh stackTraceHook) Run(e *Event, level Level, msg string) {
-1
View File
@@ -7,7 +7,6 @@ import (
var disabledLogger *Logger
func init() {
SetGlobalLevel(TraceLevel)
l := Nop()
disabledLogger = &l
}
+15 -25
View File
@@ -5,6 +5,7 @@ import (
"net"
"os"
"runtime"
"strconv"
"sync"
"time"
)
@@ -105,20 +106,10 @@ func (e *Event) Msg(msg string) {
e.msg(msg)
}
// Send is equivalent to calling Msg("").
// Msgf sends the event with formated msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
func (e *Event) Send() {
if e == nil {
return
}
e.msg("")
}
// Msgf sends the event with formatted msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
// Calling Msgf twice can have unexpected result.
// NOTICE: once this methid is called, the *Event should be disposed.
// Calling Msg twice can have unexpected result.
func (e *Event) Msgf(format string, v ...interface{}) {
if e == nil {
return
@@ -127,8 +118,13 @@ func (e *Event) Msgf(format string, v ...interface{}) {
}
func (e *Event) msg(msg string) {
for _, hook := range e.ch {
hook.Run(e, e.level, msg)
if len(e.ch) > 0 {
e.ch[0].Run(e, e.level, msg)
if len(e.ch) > 1 {
for _, hook := range e.ch[1:] {
hook.Run(e, e.level, msg)
}
}
}
if msg != "" {
e.buf = enc.AppendString(enc.AppendKey(e.buf, MessageFieldName), msg)
@@ -208,7 +204,7 @@ func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
return e
}
// EmbedObject marshals an object that implement the LogObjectMarshaler interface.
// Object marshals an object that implement the LogObjectMarshaler interface.
func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event {
if e == nil {
return e
@@ -665,14 +661,8 @@ func (e *Event) Interface(key string, i interface{}) *Event {
}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
// The argument skip is the number of stack frames to ascend
// Skip If not passed, use the global variable CallerSkipFrameCount
func (e *Event) Caller(skip ...int) *Event {
sk := CallerSkipFrameCount
if len(skip) > 0 {
sk = skip[0] + CallerSkipFrameCount
}
return e.caller(sk)
func (e *Event) Caller() *Event {
return e.caller(CallerSkipFrameCount)
}
func (e *Event) caller(skip int) *Event {
@@ -683,7 +673,7 @@ func (e *Event) caller(skip int) *Event {
if !ok {
return e
}
e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(file, line))
e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), file+":"+strconv.Itoa(line))
return e
}
+12 -39
View File
@@ -1,24 +1,7 @@
package zerolog
import (
"strconv"
"sync/atomic"
"time"
)
const (
// TimeFormatUnix defines a time format that makes time fields to be
// serialized as Unix timestamp integers.
TimeFormatUnix = ""
// TimeFormatUnixMs defines a time format that makes time fields to be
// serialized as Unix timestamp integers in milliseconds.
TimeFormatUnixMs = "UNIXMS"
// TimeFormatUnixMicro defines a time format that makes time fields to be
// serialized as Unix timestamp integers in microseconds.
TimeFormatUnixMicro = "UNIXMICRO"
)
import "time"
import "sync/atomic"
var (
// TimestampFieldName is the field name used for the timestamp field.
@@ -27,11 +10,6 @@ var (
// LevelFieldName is the field name used for the level field.
LevelFieldName = "level"
// LevelFieldMarshalFunc allows customization of global level field marshaling
LevelFieldMarshalFunc = func(l Level) string {
return l.String()
}
// MessageFieldName is the field name used for the message field.
MessageFieldName = "message"
@@ -44,11 +22,6 @@ var (
// CallerSkipFrameCount is the number of stack frames to skip to find the caller.
CallerSkipFrameCount = 2
// CallerMarshalFunc allows customization of global caller marshaling
CallerMarshalFunc = func(file string, line int) string {
return file + ":" + strconv.Itoa(line)
}
// ErrorStackFieldName is the field name used for error stacks.
ErrorStackFieldName = "stack"
@@ -60,9 +33,9 @@ var (
return err
}
// TimeFieldFormat defines the time format of the Time field type. If set to
// TimeFormatUnix, TimeFormatUnixMs or TimeFormatUnixMicro, the time is formatted as an UNIX
// timestamp as integer.
// TimeFieldFormat defines the time format of the Time field type.
// If set to an empty string, the time is formatted as an UNIX timestamp
// as integer.
TimeFieldFormat = time.RFC3339
// TimestampFunc defines the function called to generate a timestamp.
@@ -83,8 +56,8 @@ var (
)
var (
gLevel = new(int32)
disableSampling = new(int32)
gLevel = new(uint32)
disableSampling = new(uint32)
)
// SetGlobalLevel sets the global override for log level. If this
@@ -92,23 +65,23 @@ var (
//
// To globally disable logs, set GlobalLevel to Disabled.
func SetGlobalLevel(l Level) {
atomic.StoreInt32(gLevel, int32(l))
atomic.StoreUint32(gLevel, uint32(l))
}
// GlobalLevel returns the current global log level
func GlobalLevel() Level {
return Level(atomic.LoadInt32(gLevel))
return Level(atomic.LoadUint32(gLevel))
}
// DisableSampling will disable sampling in all Loggers if true.
func DisableSampling(v bool) {
var i int32
var i uint32
if v {
i = 1
}
atomic.StoreInt32(disableSampling, i)
atomic.StoreUint32(disableSampling, i)
}
func samplingDisabled() bool {
return atomic.LoadInt32(disableSampling) == 1
return atomic.LoadUint32(disableSampling) == 1
}
-8
View File
@@ -1,9 +1 @@
module github.com/rs/zerolog
require (
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/pkg/errors v0.8.1
github.com/rs/xid v1.2.1
github.com/zenazn/goji v0.9.0
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74
)
-16
View File
@@ -1,16 +0,0 @@
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74 h1:4cFkmztxtMslUX2SctSl+blCyXfpzhGOy9LhKAqSMA4=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-7
View File
@@ -1,7 +0,0 @@
// +build go1.12
package zerolog
// Since go 1.12, some auto generated init functions are hidden from
// runtime.Caller.
const contextCallerSkipFrameCount = 2
-16
View File
@@ -171,22 +171,6 @@ func RequestIDHandler(fieldKey, headerName string) func(next http.Handler) http.
}
}
// CustomHeaderHandler adds given header from request's header as a field to
// the context's logger using fieldKey as field key.
func CustomHeaderHandler(fieldKey, header string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if val := r.Header.Get(header); val != "" {
log := zerolog.Ctx(r.Context())
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str(fieldKey, val)
})
}
next.ServeHTTP(w, r)
})
}
}
// AccessHandler returns a handler that call f after each request.
func AccessHandler(f func(r *http.Request, status, size int, duration time.Duration)) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
-18
View File
@@ -182,24 +182,6 @@ func TestRequestIDHandler(t *testing.T) {
h.ServeHTTP(httptest.NewRecorder(), r)
}
func TestCustomHeaderHandler(t *testing.T) {
out := &bytes.Buffer{}
r := &http.Request{
Header: http.Header{
"X-Request-Id": []string{"514bbe5bb5251c92bd07a9846f4a1ab6"},
},
}
h := CustomHeaderHandler("reqID", "X-Request-Id")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
l := FromRequest(r)
l.Log().Msg("")
}))
h = NewHandler(zerolog.New(out))(h)
h.ServeHTTP(nil, r)
if want, got := `{"reqID":"514bbe5bb5251c92bd07a9846f4a1ab6"}`+"\n", decodeIfBinary(out); want != got {
t.Errorf("Invalid log output, got: %s, want: %s", got, want)
}
}
func TestCombinedHandlers(t *testing.T) {
out := &bytes.Buffer{}
r := &http.Request{
+1 -5
View File
@@ -17,16 +17,12 @@ func (h HookFunc) Run(e *Event, level Level, message string) {
// LevelHook applies a different hook for each level.
type LevelHook struct {
NoLevelHook, TraceHook, DebugHook, InfoHook, WarnHook, ErrorHook, FatalHook, PanicHook Hook
NoLevelHook, DebugHook, InfoHook, WarnHook, ErrorHook, FatalHook, PanicHook Hook
}
// Run implements the Hook interface.
func (h LevelHook) Run(e *Event, level Level, message string) {
switch level {
case TraceLevel:
if h.TraceHook != nil {
h.TraceHook.Run(e, level, message)
}
case DebugLevel:
if h.DebugHook != nil {
h.DebugHook.Run(e, level, message)
+3 -3
View File
@@ -24,9 +24,9 @@ func (Encoder) AppendEndMarker(dst []byte) []byte {
// AppendObjectData takes an object in form of a byte array and appends to dst.
func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
// BeginMarker is present in the dst, which
// should not be copied when appending to existing data.
return append(dst, o[1:]...)
// BeginMarker is present in the dst, which
// should not be copied when appending to existing data.
return append(dst, o[1:]...)
}
// AppendArrayStart adds markers to indicate the start of an array.
+2 -32
View File
@@ -5,23 +5,11 @@ import (
"time"
)
const (
// Import from zerolog/global.go
timeFormatUnix = ""
timeFormatUnixMs = "UNIXMS"
timeFormatUnixMicro = "UNIXMICRO"
)
// AppendTime formats the input time with the given format
// and appends the encoded string to the input byte slice.
func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
switch format {
case timeFormatUnix:
if format == "" {
return e.AppendInt64(dst, t.Unix())
case timeFormatUnixMs:
return e.AppendInt64(dst, t.UnixNano()/1000000)
case timeFormatUnixMicro:
return e.AppendInt64(dst, t.UnixNano()/1000)
}
return append(t.AppendFormat(append(dst, '"'), format), '"')
}
@@ -29,11 +17,8 @@ func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
// AppendTimes converts the input times with the given format
// and appends the encoded string list to the input byte slice.
func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte {
switch format {
case timeFormatUnix:
if format == "" {
return appendUnixTimes(dst, vals)
case timeFormatUnixMs:
return appendUnixMsTimes(dst, vals)
}
if len(vals) == 0 {
return append(dst, '[', ']')
@@ -64,21 +49,6 @@ func appendUnixTimes(dst []byte, vals []time.Time) []byte {
return dst
}
func appendUnixMsTimes(dst []byte, vals []time.Time) []byte {
if len(vals) == 0 {
return append(dst, '[', ']')
}
dst = append(dst, '[')
dst = strconv.AppendInt(dst, vals[0].UnixNano()/1000000, 10)
if len(vals) > 1 {
for _, t := range vals[1:] {
dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/1000000, 10)
}
}
dst = append(dst, ']')
return dst
}
// AppendDuration formats the input duration with the given unit & format
// and appends the encoded string to the input byte slice.
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
+5 -10
View File
@@ -373,17 +373,12 @@ func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
// AppendObjectData takes in an object that is already in a byte array
// and adds it to the dst.
func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
// Three conditions apply here:
// 1. new content starts with '{' - which should be dropped OR
// 2. new content starts with '{' - which should be replaced with ','
// to separate with existing content OR
// 3. existing content has already other fields
// Two conditions we want to put a ',' between existing content and
// new content:
// 1. new content starts with '{' - which shd be dropped OR
// 2. existing content has already other fields
if o[0] == '{' {
if len(dst) == 0 {
o = o[1:]
} else {
o[0] = ','
}
o[0] = ','
} else if len(dst) > 1 {
dst = append(dst, ',')
}
-20
View File
@@ -165,23 +165,3 @@ func Test_appendMac(t *testing.T) {
})
}
}
func Test_appendObjectData(t *testing.T) {
tests := []struct {
dst []byte
obj []byte
want []byte
}{
{[]byte{}, []byte(`{"foo":"bar"}`), []byte(`"foo":"bar"}`)},
{[]byte(`{"qux":"quz"`), []byte(`{"foo":"bar"}`), []byte(`{"qux":"quz","foo":"bar"}`)},
{[]byte{}, []byte(`"foo":"bar"`), []byte(`"foo":"bar"`)},
{[]byte(`{"qux":"quz"`), []byte(`"foo":"bar"`), []byte(`{"qux":"quz","foo":"bar"`)},
}
for _, tt := range tests {
t.Run("ObjectData", func(t *testing.T) {
if got := enc.AppendObjectData(tt.dst, tt.obj); !reflect.DeepEqual(got, tt.want) {
t.Errorf("appendObjectData() = %s, want %s", got, tt.want)
}
})
}
}
+3 -6
View File
@@ -20,12 +20,11 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/coreos/go-systemd/journal"
"github.com/rs/zerolog"
"github.com/rs/zerolog/internal/cbor"
"io"
"strings"
)
const defaultJournalDPrio = journal.PriNotice
@@ -48,8 +47,6 @@ func levelToJPrio(zLevel string) journal.Priority {
lvl, _ := zerolog.ParseLevel(zLevel)
switch lvl {
case zerolog.TraceLevel:
return journal.PriDebug
case zerolog.DebugLevel:
return journal.PriDebug
case zerolog.InfoLevel:
@@ -70,7 +67,7 @@ func levelToJPrio(zLevel string) journal.Priority {
func (w journalWriter) Write(p []byte) (n int, err error) {
if !journal.Enabled() {
err = fmt.Errorf("cannot connect to journalD")
err = fmt.Errorf("Cannot connect to journalD!!")
return
}
var event map[string]interface{}
+12 -45
View File
@@ -94,8 +94,8 @@
// Msg("dup")
// // Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
//
// In this case, many consumers will take the last value,
// but this is not guaranteed; check yours if in doubt.
// However, its not a big deal though as JSON accepts dup keys,
// the last one prevails.
package zerolog
import (
@@ -107,7 +107,7 @@ import (
)
// Level defines log levels.
type Level int8
type Level uint8
const (
// DebugLevel defines debug log level.
@@ -126,15 +126,10 @@ const (
NoLevel
// Disabled disables the logger.
Disabled
// TraceLevel defines trace log level.
TraceLevel Level = -1
)
func (l Level) String() string {
switch l {
case TraceLevel:
return "trace"
case DebugLevel:
return "debug"
case InfoLevel:
@@ -157,21 +152,19 @@ func (l Level) String() string {
// returns an error if the input string does not match known values.
func ParseLevel(levelStr string) (Level, error) {
switch levelStr {
case LevelFieldMarshalFunc(TraceLevel):
return TraceLevel, nil
case LevelFieldMarshalFunc(DebugLevel):
case DebugLevel.String():
return DebugLevel, nil
case LevelFieldMarshalFunc(InfoLevel):
case InfoLevel.String():
return InfoLevel, nil
case LevelFieldMarshalFunc(WarnLevel):
case WarnLevel.String():
return WarnLevel, nil
case LevelFieldMarshalFunc(ErrorLevel):
case ErrorLevel.String():
return ErrorLevel, nil
case LevelFieldMarshalFunc(FatalLevel):
case FatalLevel.String():
return FatalLevel, nil
case LevelFieldMarshalFunc(PanicLevel):
case PanicLevel.String():
return PanicLevel, nil
case LevelFieldMarshalFunc(NoLevel):
case NoLevel.String():
return NoLevel, nil
}
return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
@@ -205,7 +198,7 @@ func New(w io.Writer) Logger {
if !ok {
lw = levelWriterAdapter{w}
}
return Logger{w: lw, level: TraceLevel}
return Logger{w: lw}
}
// Nop returns a disabled logger for which all operation are no-op.
@@ -258,11 +251,6 @@ func (l Logger) Level(lvl Level) Logger {
return l
}
// GetLevel returns the current Level of l.
func (l Logger) GetLevel() Level {
return l.level
}
// Sample returns a logger with the s sampler.
func (l Logger) Sample(s Sampler) Logger {
l.sampler = s
@@ -275,13 +263,6 @@ func (l Logger) Hook(h Hook) Logger {
return l
}
// Trace starts a new message with trace level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Trace() *Event {
return l.newEvent(TraceLevel, nil)
}
// Debug starts a new message with debug level.
//
// You must call Msg on the returned event in order to send the event.
@@ -310,18 +291,6 @@ func (l *Logger) Error() *Event {
return l.newEvent(ErrorLevel, nil)
}
// Err starts a new message with error level with err as a field if not nil or
// with info level if err is nil.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Err(err error) *Event {
if err != nil {
return l.Error().Err(err)
}
return l.Info()
}
// Fatal starts a new message with fatal level. The os.Exit(1) function
// is called by the Msg method, which terminates the program immediately.
//
@@ -345,8 +314,6 @@ func (l *Logger) Panic() *Event {
// You must call Msg on the returned event in order to send the event.
func (l *Logger) WithLevel(level Level) *Event {
switch level {
case TraceLevel:
return l.Trace()
case DebugLevel:
return l.Debug()
case InfoLevel:
@@ -413,7 +380,7 @@ func (l *Logger) newEvent(level Level, done func(string)) *Event {
e.done = done
e.ch = l.hooks
if level != NoLevel {
e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
e.Str(LevelFieldName, level.String())
}
if l.context != nil && len(l.context) > 0 {
e.buf = enc.AppendObjectData(e.buf, l.context)
-15
View File
@@ -37,21 +37,6 @@ func Hook(h zerolog.Hook) zerolog.Logger {
return Logger.Hook(h)
}
// Err starts a new message with error level with err as a field if not nil or
// with info level if err is nil.
//
// You must call Msg on the returned event in order to send the event.
func Err(err error) *zerolog.Event {
return Logger.Err(err)
}
// Trace starts a new message with trace level.
//
// You must call Msg on the returned event in order to send the event.
func Trace() *zerolog.Event {
return Logger.Trace()
}
// Debug starts a new message with debug level.
//
// You must call Msg on the returned event in order to send the event.
-19
View File
@@ -54,25 +54,6 @@ func ExampleLog() {
// Output: {"time":1199811905,"message":"hello world"}
}
// Example of a conditional level based on the presence of an error.
func ExampleErr() {
setup()
err := errors.New("some error")
log.Err(err).Msg("hello world")
log.Err(nil).Msg("hello world")
// Output: {"level":"error","error":"some error","time":1199811905,"message":"hello world"}
// {"level":"info","time":1199811905,"message":"hello world"}
}
// Example of a log at a particular "level" (in this case, "trace")
func ExampleTrace() {
setup()
log.Trace().Msg("hello world")
// Output: {"level":"trace","time":1199811905,"message":"hello world"}
}
// Example of a log at a particular "level" (in this case, "debug")
func ExampleDebug() {
setup()
-11
View File
@@ -95,17 +95,6 @@ func ExampleLogger_Printf() {
// Output: {"level":"debug","message":"hello world"}
}
func ExampleLogger_Trace() {
log := zerolog.New(os.Stdout)
log.Trace().
Str("foo", "bar").
Int("n", 123).
Msg("hello world")
// Output: {"level":"trace","foo":"bar","n":123,"message":"hello world"}
}
func ExampleLogger_Debug() {
log := zerolog.New(os.Stdout)
+8 -115
View File
@@ -7,8 +7,6 @@ import (
"net"
"reflect"
"runtime"
"strconv"
"strings"
"testing"
"time"
)
@@ -107,20 +105,6 @@ func TestWith(t *testing.T) {
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
// Validate CallerWithSkipFrameCount.
out.Reset()
_, file, line, _ = runtime.Caller(0)
caller = fmt.Sprintf("%s:%d", file, line+5)
log = ctx.CallerWithSkipFrameCount(3).Logger()
func() {
log.Log().Msg("")
}()
// The above line is a little contrived, but the line above should be the line due
// to the extra frame skip.
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}
func TestFieldsMap(t *testing.T) {
@@ -453,24 +437,6 @@ func TestLevel(t *testing.T) {
})
}
func TestGetLevel(t *testing.T) {
levels := []Level{
DebugLevel,
InfoLevel,
WarnLevel,
ErrorLevel,
FatalLevel,
PanicLevel,
NoLevel,
Disabled,
}
for _, level := range levels {
if got, want := New(nil).Level(level).GetLevel(), level; got != want {
t.Errorf("GetLevel() = %v, want: %v", got, want)
}
}
}
func TestSampling(t *testing.T) {
out := &bytes.Buffer{}
log := New(out).Sample(&BasicSampler{N: 2})
@@ -526,34 +492,30 @@ func TestLevelWriter(t *testing.T) {
}{},
}
log := New(lw)
log.Trace().Msg("0")
log.Debug().Msg("1")
log.Info().Msg("2")
log.Warn().Msg("3")
log.Error().Msg("4")
log.Log().Msg("nolevel-1")
log.WithLevel(TraceLevel).Msg("5")
log.WithLevel(DebugLevel).Msg("6")
log.WithLevel(InfoLevel).Msg("7")
log.WithLevel(WarnLevel).Msg("8")
log.WithLevel(ErrorLevel).Msg("9")
log.WithLevel(DebugLevel).Msg("5")
log.WithLevel(InfoLevel).Msg("6")
log.WithLevel(WarnLevel).Msg("7")
log.WithLevel(ErrorLevel).Msg("8")
log.WithLevel(NoLevel).Msg("nolevel-2")
want := []struct {
l Level
p string
}{
{TraceLevel, `{"level":"trace","message":"0"}` + "\n"},
{DebugLevel, `{"level":"debug","message":"1"}` + "\n"},
{InfoLevel, `{"level":"info","message":"2"}` + "\n"},
{WarnLevel, `{"level":"warn","message":"3"}` + "\n"},
{ErrorLevel, `{"level":"error","message":"4"}` + "\n"},
{NoLevel, `{"message":"nolevel-1"}` + "\n"},
{TraceLevel, `{"level":"trace","message":"5"}` + "\n"},
{DebugLevel, `{"level":"debug","message":"6"}` + "\n"},
{InfoLevel, `{"level":"info","message":"7"}` + "\n"},
{WarnLevel, `{"level":"warn","message":"8"}` + "\n"},
{ErrorLevel, `{"level":"error","message":"9"}` + "\n"},
{DebugLevel, `{"level":"debug","message":"5"}` + "\n"},
{InfoLevel, `{"level":"info","message":"6"}` + "\n"},
{WarnLevel, `{"level":"warn","message":"7"}` + "\n"},
{ErrorLevel, `{"level":"error","message":"8"}` + "\n"},
{NoLevel, `{"message":"nolevel-2"}` + "\n"},
}
if got := lw.ops; !reflect.DeepEqual(got, want) {
@@ -679,75 +641,6 @@ func TestErrorMarshalFunc(t *testing.T) {
}
}
func TestCallerMarshalFunc(t *testing.T) {
out := &bytes.Buffer{}
log := New(out)
// test default behaviour this is really brittle due to the line numbers
// actually mattering for validation
_, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+2)
log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
// test custom behavior. In this case we'll take just the last directory
origCallerMarshalFunc := CallerMarshalFunc
defer func() { CallerMarshalFunc = origCallerMarshalFunc }()
CallerMarshalFunc = func(file string, line int) string {
parts := strings.Split(file, "/")
if len(parts) > 1 {
return strings.Join(parts[len(parts)-2:], "/") + ":" + strconv.Itoa(line)
}
return file + ":" + strconv.Itoa(line)
}
_, file, line, _ = runtime.Caller(0)
caller = CallerMarshalFunc(file, line+2)
log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}
func TestLevelFieldMarshalFunc(t *testing.T) {
origLevelFieldMarshalFunc := LevelFieldMarshalFunc
LevelFieldMarshalFunc = func(l Level) string {
return strings.ToUpper(l.String())
}
defer func() {
LevelFieldMarshalFunc = origLevelFieldMarshalFunc
}()
out := &bytes.Buffer{}
log := New(out)
log.Debug().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"DEBUG","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Info().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"INFO","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Warn().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"WARN","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Error().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"ERROR","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
}
type errWriter struct {
error
}
-5
View File
@@ -1,5 +0,0 @@
// +build !go1.12
package zerolog
const contextCallerSkipFrameCount = 3
+2 -10
View File
@@ -46,12 +46,8 @@ type BasicSampler struct {
// Sample implements the Sampler interface.
func (s *BasicSampler) Sample(lvl Level) bool {
n := s.N
if n == 1 {
return true
}
c := atomic.AddUint32(&s.counter, 1)
return c%n == 1
return c%s.N == s.N-1
}
// BurstSampler lets Burst events pass per Period then pass the decision to
@@ -104,15 +100,11 @@ func (s *BurstSampler) inc() uint32 {
// LevelSampler applies a different sampler for each level.
type LevelSampler struct {
TraceSampler, DebugSampler, InfoSampler, WarnSampler, ErrorSampler Sampler
DebugSampler, InfoSampler, WarnSampler, ErrorSampler Sampler
}
func (s LevelSampler) Sample(lvl Level) bool {
switch lvl {
case TraceLevel:
if s.TraceSampler != nil {
return s.TraceSampler.Sample(lvl)
}
case DebugLevel:
if s.DebugSampler != nil {
return s.DebugSampler.Sample(lvl)
-2
View File
@@ -35,8 +35,6 @@ func (sw syslogWriter) Write(p []byte) (n int, err error) {
// WriteLevel implements LevelWriter interface.
func (sw syslogWriter) WriteLevel(level Level, p []byte) (n int, err error) {
switch level {
case TraceLevel:
err = sw.w.Trace(string(p))
case DebugLevel:
err = sw.w.Debug(string(p))
case InfoLevel:
-6
View File
@@ -17,10 +17,6 @@ type syslogTestWriter struct {
func (w *syslogTestWriter) Write(p []byte) (int, error) {
return 0, nil
}
func (w *syslogTestWriter) Trace(m string) error {
w.events = append(w.events, syslogEvent{"Trace", m})
return nil
}
func (w *syslogTestWriter) Debug(m string) error {
w.events = append(w.events, syslogEvent{"Debug", m})
return nil
@@ -49,14 +45,12 @@ func (w *syslogTestWriter) Crit(m string) error {
func TestSyslogWriter(t *testing.T) {
sw := &syslogTestWriter{}
log := New(SyslogLevelWriter(sw))
log.Trace().Msg("trace")
log.Debug().Msg("debug")
log.Info().Msg("info")
log.Warn().Msg("warn")
log.Error().Msg("error")
log.Log().Msg("nolevel")
want := []syslogEvent{
{"Trace", `{"level":"trace","message":"trace"}` + "\n"},
{"Debug", `{"level":"debug","message":"debug"}` + "\n"},
{"Info", `{"level":"info","message":"info"}` + "\n"},
{"Warning", `{"level":"warn","message":"warn"}` + "\n"},