942 lines
30 KiB
Go
942 lines
30 KiB
Go
package zerolog
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLog(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), "{}\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("one-field", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Str("foo", "bar").Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("two-field", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().
|
|
Str("foo", "bar").
|
|
Int("n", 123).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","n":123}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestInfo(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Info().Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("one-field", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Info().Str("foo", "bar").Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info","foo":"bar"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("two-field", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Info().
|
|
Str("foo", "bar").
|
|
Int("n", 123).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info","foo":"bar","n":123}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestEmptyLevelFieldName(t *testing.T) {
|
|
fieldName := LevelFieldName
|
|
LevelFieldName = ""
|
|
|
|
t.Run("empty setting", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Info().
|
|
Str("foo", "bar").
|
|
Int("n", 123).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","n":123}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
LevelFieldName = fieldName
|
|
}
|
|
|
|
func TestWith(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
ctx := New(out).With().
|
|
Str("string", "foo").
|
|
Stringer("stringer", net.IP{127, 0, 0, 1}).
|
|
Stringer("stringer_nil", nil).
|
|
Bytes("bytes", []byte("bar")).
|
|
Hex("hex", []byte{0x12, 0xef}).
|
|
RawJSON("json", []byte(`{"some":"json"}`)).
|
|
AnErr("some_err", nil).
|
|
Err(errors.New("some error")).
|
|
Bool("bool", true).
|
|
Int("int", 1).
|
|
Int8("int8", 2).
|
|
Int16("int16", 3).
|
|
Int32("int32", 4).
|
|
Int64("int64", 5).
|
|
Uint("uint", 6).
|
|
Uint8("uint8", 7).
|
|
Uint16("uint16", 8).
|
|
Uint32("uint32", 9).
|
|
Uint64("uint64", 10).
|
|
Float32("float32", 11.101).
|
|
Float64("float64", 12.30303).
|
|
Time("time", time.Time{})
|
|
_, file, line, _ := runtime.Caller(0)
|
|
caller := fmt.Sprintf("%s:%d", file, line+3)
|
|
log := ctx.Caller().Logger()
|
|
log.Log().Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","stringer":"127.0.0.1","stringer_nil":null,"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","stringer":"127.0.0.1","stringer_nil":null,"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) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Fields(map[string]interface{}{
|
|
"nil": nil,
|
|
"string": "foo",
|
|
"bytes": []byte("bar"),
|
|
"error": errors.New("some error"),
|
|
"bool": true,
|
|
"int": int(1),
|
|
"int8": int8(2),
|
|
"int16": int16(3),
|
|
"int32": int32(4),
|
|
"int64": int64(5),
|
|
"uint": uint(6),
|
|
"uint8": uint8(7),
|
|
"uint16": uint16(8),
|
|
"uint32": uint32(9),
|
|
"uint64": uint64(10),
|
|
"float32": float32(11),
|
|
"float64": float64(12),
|
|
"ipv6": net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},
|
|
"dur": 1 * time.Second,
|
|
"time": time.Time{},
|
|
"obj": obj{"a", "b", 1},
|
|
}).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":true,"bytes":"bar","dur":1000,"error":"some error","float32":11,"float64":12,"int":1,"int16":3,"int32":4,"int64":5,"int8":2,"ipv6":"2001:db8:85a3::8a2e:370:7334","nil":null,"obj":{"Pub":"a","Tag":"b","priv":1},"string":"foo","time":"0001-01-01T00:00:00Z","uint":6,"uint16":8,"uint32":9,"uint64":10,"uint8":7}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsMapPnt(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Fields(map[string]interface{}{
|
|
"string": new(string),
|
|
"bool": new(bool),
|
|
"int": new(int),
|
|
"int8": new(int8),
|
|
"int16": new(int16),
|
|
"int32": new(int32),
|
|
"int64": new(int64),
|
|
"uint": new(uint),
|
|
"uint8": new(uint8),
|
|
"uint16": new(uint16),
|
|
"uint32": new(uint32),
|
|
"uint64": new(uint64),
|
|
"float32": new(float32),
|
|
"float64": new(float64),
|
|
"dur": new(time.Duration),
|
|
"time": new(time.Time),
|
|
}).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":false,"dur":0,"float32":0,"float64":0,"int":0,"int16":0,"int32":0,"int64":0,"int8":0,"string":"","time":"0001-01-01T00:00:00Z","uint":0,"uint16":0,"uint32":0,"uint64":0,"uint8":0}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsMapNilPnt(t *testing.T) {
|
|
var (
|
|
stringPnt *string
|
|
boolPnt *bool
|
|
intPnt *int
|
|
int8Pnt *int8
|
|
int16Pnt *int16
|
|
int32Pnt *int32
|
|
int64Pnt *int64
|
|
uintPnt *uint
|
|
uint8Pnt *uint8
|
|
uint16Pnt *uint16
|
|
uint32Pnt *uint32
|
|
uint64Pnt *uint64
|
|
float32Pnt *float32
|
|
float64Pnt *float64
|
|
durPnt *time.Duration
|
|
timePnt *time.Time
|
|
)
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
fields := map[string]interface{}{
|
|
"string": stringPnt,
|
|
"bool": boolPnt,
|
|
"int": intPnt,
|
|
"int8": int8Pnt,
|
|
"int16": int16Pnt,
|
|
"int32": int32Pnt,
|
|
"int64": int64Pnt,
|
|
"uint": uintPnt,
|
|
"uint8": uint8Pnt,
|
|
"uint16": uint16Pnt,
|
|
"uint32": uint32Pnt,
|
|
"uint64": uint64Pnt,
|
|
"float32": float32Pnt,
|
|
"float64": float64Pnt,
|
|
"dur": durPnt,
|
|
"time": timePnt,
|
|
}
|
|
|
|
log.Log().Fields(fields).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":null,"dur":null,"float32":null,"float64":null,"int":null,"int16":null,"int32":null,"int64":null,"int8":null,"string":null,"time":null,"uint":null,"uint16":null,"uint32":null,"uint64":null,"uint8":null}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsSlice(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Fields([]interface{}{
|
|
"nil", nil,
|
|
"string", "foo",
|
|
"bytes", []byte("bar"),
|
|
"error", errors.New("some error"),
|
|
"bool", true,
|
|
"int", int(1),
|
|
"int8", int8(2),
|
|
"int16", int16(3),
|
|
"int32", int32(4),
|
|
"int64", int64(5),
|
|
"uint", uint(6),
|
|
"uint8", uint8(7),
|
|
"uint16", uint16(8),
|
|
"uint32", uint32(9),
|
|
"uint64", uint64(10),
|
|
"float32", float32(11),
|
|
"float64", float64(12),
|
|
"ipv6", net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},
|
|
"dur", 1 * time.Second,
|
|
"time", time.Time{},
|
|
"obj", obj{"a", "b", 1},
|
|
}).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"nil":null,"string":"foo","bytes":"bar","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,"float64":12,"ipv6":"2001:db8:85a3::8a2e:370:7334","dur":1000,"time":"0001-01-01T00:00:00Z","obj":{"Pub":"a","Tag":"b","priv":1}}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsSliceExtraneous(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Fields([]interface{}{
|
|
"string", "foo",
|
|
"error", errors.New("some error"),
|
|
32, "valueForNonStringKey",
|
|
"bool", true,
|
|
"int", int(1),
|
|
"keyWithoutValue",
|
|
}).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","error":"some error","bool":true,"int":1}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsNotMapSlice(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().
|
|
Fields(obj{"a", "b", 1}).
|
|
Fields("string").
|
|
Fields(1).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFields(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
now := time.Now()
|
|
_, file, line, _ := runtime.Caller(0)
|
|
caller := fmt.Sprintf("%s:%d", file, line+3)
|
|
log.Log().
|
|
Caller().
|
|
Str("string", "foo").
|
|
Stringer("stringer", net.IP{127, 0, 0, 1}).
|
|
Stringer("stringer_nil", nil).
|
|
Bytes("bytes", []byte("bar")).
|
|
Hex("hex", []byte{0x12, 0xef}).
|
|
RawJSON("json", []byte(`{"some":"json"}`)).
|
|
Func(func(e *Event) { e.Str("func", "func_output") }).
|
|
AnErr("some_err", nil).
|
|
Err(errors.New("some error")).
|
|
Bool("bool", true).
|
|
Int("int", 1).
|
|
Int8("int8", 2).
|
|
Int16("int16", 3).
|
|
Int32("int32", 4).
|
|
Int64("int64", 5).
|
|
Uint("uint", 6).
|
|
Uint8("uint8", 7).
|
|
Uint16("uint16", 8).
|
|
Uint32("uint32", 9).
|
|
Uint64("uint64", 10).
|
|
IPAddr("IPv4", net.IP{192, 168, 0, 100}).
|
|
IPAddr("IPv6", net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34}).
|
|
MACAddr("Mac", net.HardwareAddr{0x00, 0x14, 0x22, 0x01, 0x23, 0x45}).
|
|
IPPrefix("Prefix", net.IPNet{IP: net.IP{192, 168, 0, 100}, Mask: net.CIDRMask(24, 32)}).
|
|
Float32("float32", 11.1234).
|
|
Float64("float64", 12.321321321).
|
|
Dur("dur", 1*time.Second).
|
|
Time("time", time.Time{}).
|
|
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"func":"func_output","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,"IPv4":"192.168.0.100","IPv6":"2001:db8:85a3::8a2e:370:7334","Mac":"00:14:22:01:23:45","Prefix":"192.168.0.100/24","float32":11.1234,"float64":12.321321321,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsArrayEmpty(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().
|
|
Strs("string", []string{}).
|
|
Errs("err", []error{}).
|
|
Bools("bool", []bool{}).
|
|
Ints("int", []int{}).
|
|
Ints8("int8", []int8{}).
|
|
Ints16("int16", []int16{}).
|
|
Ints32("int32", []int32{}).
|
|
Ints64("int64", []int64{}).
|
|
Uints("uint", []uint{}).
|
|
Uints8("uint8", []uint8{}).
|
|
Uints16("uint16", []uint16{}).
|
|
Uints32("uint32", []uint32{}).
|
|
Uints64("uint64", []uint64{}).
|
|
Floats32("float32", []float32{}).
|
|
Floats64("float64", []float64{}).
|
|
Durs("dur", []time.Duration{}).
|
|
Times("time", []time.Time{}).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":[],"err":[],"bool":[],"int":[],"int8":[],"int16":[],"int32":[],"int64":[],"uint":[],"uint8":[],"uint16":[],"uint32":[],"uint64":[],"float32":[],"float64":[],"dur":[],"time":[]}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsArraySingleElement(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().
|
|
Strs("string", []string{"foo"}).
|
|
Errs("err", []error{errors.New("some error")}).
|
|
Bools("bool", []bool{true}).
|
|
Ints("int", []int{1}).
|
|
Ints8("int8", []int8{2}).
|
|
Ints16("int16", []int16{3}).
|
|
Ints32("int32", []int32{4}).
|
|
Ints64("int64", []int64{5}).
|
|
Uints("uint", []uint{6}).
|
|
Uints8("uint8", []uint8{7}).
|
|
Uints16("uint16", []uint16{8}).
|
|
Uints32("uint32", []uint32{9}).
|
|
Uints64("uint64", []uint64{10}).
|
|
Floats32("float32", []float32{11}).
|
|
Floats64("float64", []float64{12}).
|
|
Durs("dur", []time.Duration{1 * time.Second}).
|
|
Times("time", []time.Time{{}}).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":["foo"],"err":["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],"float64":[12],"dur":[1000],"time":["0001-01-01T00:00:00Z"]}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsArrayMultipleElement(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().
|
|
Strs("string", []string{"foo", "bar"}).
|
|
Errs("err", []error{errors.New("some error"), nil}).
|
|
Bools("bool", []bool{true, false}).
|
|
Ints("int", []int{1, 0}).
|
|
Ints8("int8", []int8{2, 0}).
|
|
Ints16("int16", []int16{3, 0}).
|
|
Ints32("int32", []int32{4, 0}).
|
|
Ints64("int64", []int64{5, 0}).
|
|
Uints("uint", []uint{6, 0}).
|
|
Uints8("uint8", []uint8{7, 0}).
|
|
Uints16("uint16", []uint16{8, 0}).
|
|
Uints32("uint32", []uint32{9, 0}).
|
|
Uints64("uint64", []uint64{10, 0}).
|
|
Floats32("float32", []float32{11, 0}).
|
|
Floats64("float64", []float64{12, 0}).
|
|
Durs("dur", []time.Duration{1 * time.Second, 0}).
|
|
Times("time", []time.Time{{}, {}}).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":["foo","bar"],"err":["some error",null],"bool":[true,false],"int":[1,0],"int8":[2,0],"int16":[3,0],"int32":[4,0],"int64":[5,0],"uint":[6,0],"uint8":[7,0],"uint16":[8,0],"uint32":[9,0],"uint64":[10,0],"float32":[11,0],"float64":[12,0],"dur":[1000,0],"time":["0001-01-01T00:00:00Z","0001-01-01T00:00:00Z"]}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFieldsDisabled(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(InfoLevel)
|
|
now := time.Now()
|
|
log.Debug().
|
|
Str("string", "foo").
|
|
Bytes("bytes", []byte("bar")).
|
|
Hex("hex", []byte{0x12, 0xef}).
|
|
AnErr("some_err", nil).
|
|
Err(errors.New("some error")).
|
|
Func(func(e *Event) { e.Str("func", "func_output") }).
|
|
Bool("bool", true).
|
|
Int("int", 1).
|
|
Int8("int8", 2).
|
|
Int16("int16", 3).
|
|
Int32("int32", 4).
|
|
Int64("int64", 5).
|
|
Uint("uint", 6).
|
|
Uint8("uint8", 7).
|
|
Uint16("uint16", 8).
|
|
Uint32("uint32", 9).
|
|
Uint64("uint64", 10).
|
|
Float32("float32", 11).
|
|
Float64("float64", 12).
|
|
Dur("dur", 1*time.Second).
|
|
Time("time", time.Time{}).
|
|
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
|
Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestMsgf(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"one two 3.4 5 six"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestWithAndFieldsCombined(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).With().Str("f1", "val").Str("f2", "val").Logger()
|
|
log.Log().Str("f3", "val").Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"f1":"val","f2":"val","f3":"val"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestLevel(t *testing.T) {
|
|
t.Run("Disabled", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(Disabled)
|
|
log.Info().Msg("test")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("NoLevel/Disabled", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(Disabled)
|
|
log.Log().Msg("test")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("NoLevel/Info", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(InfoLevel)
|
|
log.Log().Msg("test")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("NoLevel/Panic", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(PanicLevel)
|
|
log.Log().Msg("test")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("NoLevel/WithLevel", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(InfoLevel)
|
|
log.WithLevel(NoLevel).Msg("test")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("Info", func(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out).Level(InfoLevel)
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
|
|
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})
|
|
log.Log().Int("i", 1).Msg("")
|
|
log.Log().Int("i", 2).Msg("")
|
|
log.Log().Int("i", 3).Msg("")
|
|
log.Log().Int("i", 4).Msg("")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), "{\"i\":1}\n{\"i\":3}\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestDiscard(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
log.Log().Discard().Str("a", "b").Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
|
|
// Double call
|
|
log.Log().Discard().Discard().Str("a", "b").Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
type levelWriter struct {
|
|
ops []struct {
|
|
l Level
|
|
p string
|
|
}
|
|
}
|
|
|
|
func (lw *levelWriter) Write(p []byte) (int, error) {
|
|
return len(p), nil
|
|
}
|
|
|
|
func (lw *levelWriter) WriteLevel(lvl Level, p []byte) (int, error) {
|
|
p = decodeIfBinaryToBytes(p)
|
|
lw.ops = append(lw.ops, struct {
|
|
l Level
|
|
p string
|
|
}{lvl, string(p)})
|
|
return len(p), nil
|
|
}
|
|
|
|
func TestLevelWriter(t *testing.T) {
|
|
lw := &levelWriter{
|
|
ops: []struct {
|
|
l Level
|
|
p string
|
|
}{},
|
|
}
|
|
|
|
// Allow extra-verbose logs.
|
|
SetGlobalLevel(TraceLevel - 1)
|
|
log := New(lw).Level(TraceLevel - 1)
|
|
|
|
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(NoLevel).Msg("nolevel-2")
|
|
log.WithLevel(-1).Msg("-1") // Same as TraceLevel
|
|
log.WithLevel(-2).Msg("-2") // Will log
|
|
log.WithLevel(-3).Msg("-3") // Will not log
|
|
|
|
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"},
|
|
{NoLevel, `{"message":"nolevel-2"}` + "\n"},
|
|
{Level(-1), `{"level":"trace","message":"-1"}` + "\n"},
|
|
{Level(-2), `{"level":"-2","message":"-2"}` + "\n"},
|
|
}
|
|
if got := lw.ops; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("invalid ops:\ngot:\n%v\nwant:\n%v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestContextTimestamp(t *testing.T) {
|
|
TimestampFunc = func() time.Time {
|
|
return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
|
|
}
|
|
defer func() {
|
|
TimestampFunc = time.Now
|
|
}()
|
|
out := &bytes.Buffer{}
|
|
log := New(out).With().Timestamp().Str("foo", "bar").Logger()
|
|
log.Log().Msg("hello world")
|
|
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestEventTimestamp(t *testing.T) {
|
|
TimestampFunc = func() time.Time {
|
|
return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
|
|
}
|
|
defer func() {
|
|
TimestampFunc = time.Now
|
|
}()
|
|
out := &bytes.Buffer{}
|
|
log := New(out).With().Str("foo", "bar").Logger()
|
|
log.Log().Timestamp().Msg("hello world")
|
|
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestOutputWithoutTimestamp(t *testing.T) {
|
|
ignoredOut := &bytes.Buffer{}
|
|
out := &bytes.Buffer{}
|
|
log := New(ignoredOut).Output(out).With().Str("foo", "bar").Logger()
|
|
log.Log().Msg("hello world")
|
|
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","message":"hello world"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestOutputWithTimestamp(t *testing.T) {
|
|
TimestampFunc = func() time.Time {
|
|
return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
|
|
}
|
|
defer func() {
|
|
TimestampFunc = time.Now
|
|
}()
|
|
ignoredOut := &bytes.Buffer{}
|
|
out := &bytes.Buffer{}
|
|
log := New(ignoredOut).Output(out).With().Timestamp().Str("foo", "bar").Logger()
|
|
log.Log().Msg("hello world")
|
|
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
type loggableError struct {
|
|
error
|
|
}
|
|
|
|
func (l loggableError) MarshalZerologObject(e *Event) {
|
|
e.Str("message", l.error.Error()+": loggableError")
|
|
}
|
|
|
|
func TestErrorMarshalFunc(t *testing.T) {
|
|
out := &bytes.Buffer{}
|
|
log := New(out)
|
|
|
|
// test default behaviour
|
|
log.Log().Err(errors.New("err")).Msg("msg")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err","message":"msg"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
out.Reset()
|
|
|
|
log.Log().Err(loggableError{errors.New("err")}).Msg("msg")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":{"message":"err: loggableError"},"message":"msg"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
out.Reset()
|
|
|
|
// test overriding the ErrorMarshalFunc
|
|
originalErrorMarshalFunc := ErrorMarshalFunc
|
|
defer func() {
|
|
ErrorMarshalFunc = originalErrorMarshalFunc
|
|
}()
|
|
|
|
ErrorMarshalFunc = func(err error) interface{} {
|
|
return err.Error() + ": marshaled string"
|
|
}
|
|
log.Log().Err(errors.New("err")).Msg("msg")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err: marshaled string","message":"msg"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
|
|
out.Reset()
|
|
ErrorMarshalFunc = func(err error) interface{} {
|
|
return errors.New(err.Error() + ": new error")
|
|
}
|
|
log.Log().Err(errors.New("err")).Msg("msg")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err: new error","message":"msg"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
|
|
out.Reset()
|
|
ErrorMarshalFunc = func(err error) interface{} {
|
|
return loggableError{err}
|
|
}
|
|
log.Log().Err(errors.New("err")).Msg("msg")
|
|
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":{"message":"err: loggableError"},"message":"msg"}`+"\n"; got != want {
|
|
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (w errWriter) Write(p []byte) (n int, err error) {
|
|
return 0, w.error
|
|
}
|
|
|
|
func TestErrorHandler(t *testing.T) {
|
|
var got error
|
|
want := errors.New("write error")
|
|
ErrorHandler = func(err error) {
|
|
got = err
|
|
}
|
|
log := New(errWriter{want})
|
|
log.Log().Msg("test")
|
|
if got != want {
|
|
t.Errorf("ErrorHandler err = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestUpdateEmptyContext(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
log := New(&buf)
|
|
|
|
log.UpdateContext(func(c Context) Context {
|
|
return c.Str("foo", "bar")
|
|
})
|
|
log.Info().Msg("no panic")
|
|
|
|
want := `{"level":"info","foo":"bar","message":"no panic"}` + "\n"
|
|
|
|
if got := decodeIfBinaryToString(buf.Bytes()); got != want {
|
|
t.Errorf("invalid log output:\ngot: %q\nwant: %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestLevel_String(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
l Level
|
|
want string
|
|
}{
|
|
{"trace", TraceLevel, "trace"},
|
|
{"debug", DebugLevel, "debug"},
|
|
{"info", InfoLevel, "info"},
|
|
{"warn", WarnLevel, "warn"},
|
|
{"error", ErrorLevel, "error"},
|
|
{"fatal", FatalLevel, "fatal"},
|
|
{"panic", PanicLevel, "panic"},
|
|
{"disabled", Disabled, "disabled"},
|
|
{"nolevel", NoLevel, ""},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := tt.l.String(); got != tt.want {
|
|
t.Errorf("String() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseLevel(t *testing.T) {
|
|
type args struct {
|
|
levelStr string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want Level
|
|
wantErr bool
|
|
}{
|
|
{"trace", args{"trace"}, TraceLevel, false},
|
|
{"debug", args{"debug"}, DebugLevel, false},
|
|
{"info", args{"info"}, InfoLevel, false},
|
|
{"warn", args{"warn"}, WarnLevel, false},
|
|
{"error", args{"error"}, ErrorLevel, false},
|
|
{"fatal", args{"fatal"}, FatalLevel, false},
|
|
{"panic", args{"panic"}, PanicLevel, false},
|
|
{"disabled", args{"disabled"}, Disabled, false},
|
|
{"nolevel", args{""}, NoLevel, false},
|
|
{"-1", args{"-1"}, TraceLevel, false},
|
|
{"-2", args{"-2"}, Level(-2), false},
|
|
{"-3", args{"-3"}, Level(-3), false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := ParseLevel(tt.args.levelStr)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("ParseLevel() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("ParseLevel() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|