mirror of
https://github.com/rs/zerolog
synced 2026-06-08 17:13:30 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f220d89e1f | |||
| 87aceba511 | |||
| 2aa3c3ae4f | |||
| eed4c2b94d | |||
| 7af653895b | |||
| c964fc4812 | |||
| 72d41dedeb | |||
| 1b37e7fcd9 | |||
| 447d0fc7f5 | |||
| 9c5f03507d | |||
| 15fc33fe89 |
@@ -189,6 +189,15 @@ c = c.Append(hlog.NewHandler(log))
|
||||
|
||||
// Install some provided extra handler to set some request's context fields.
|
||||
// Thanks to those handler, all our logs will come with some pre-populated fields.
|
||||
c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
||||
hlog.FromRequest(r).Info().
|
||||
Str("method", r.Method).
|
||||
Str("url", r.URL.String()).
|
||||
Int("status", status).
|
||||
Int("size", size).
|
||||
Dur("duration", duration).
|
||||
Msg("")
|
||||
}))
|
||||
c = c.Append(hlog.RemoteAddrHandler("ip"))
|
||||
c = c.Append(hlog.UserAgentHandler("user_agent"))
|
||||
c = c.Append(hlog.RefererHandler("referer"))
|
||||
|
||||
@@ -71,3 +71,89 @@ func BenchmarkLogFields(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkLogFieldType(b *testing.B) {
|
||||
type obj struct {
|
||||
Pub string
|
||||
Tag string `json:"tag"`
|
||||
priv int
|
||||
}
|
||||
bools := []bool{true, false, true, false, true, false, true, false, true, false}
|
||||
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
floats := []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
strings := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
|
||||
durations := []time.Duration{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
times := []time.Time{
|
||||
time.Unix(0, 0),
|
||||
time.Unix(1, 0),
|
||||
time.Unix(2, 0),
|
||||
time.Unix(3, 0),
|
||||
time.Unix(4, 0),
|
||||
time.Unix(5, 0),
|
||||
time.Unix(6, 0),
|
||||
time.Unix(7, 0),
|
||||
time.Unix(8, 0),
|
||||
time.Unix(9, 0),
|
||||
}
|
||||
o := obj{"a", "a", 0}
|
||||
errs := []error{errors.New("a"), errors.New("b"), errors.New("c"), errors.New("d"), errors.New("e")}
|
||||
types := map[string]func(e *Event) *Event{
|
||||
"Bool": func(e *Event) *Event {
|
||||
return e.Bool("k", bools[0])
|
||||
},
|
||||
"Bools": func(e *Event) *Event {
|
||||
return e.Bools("k", bools)
|
||||
},
|
||||
"Int": func(e *Event) *Event {
|
||||
return e.Int("k", ints[0])
|
||||
},
|
||||
"Ints": func(e *Event) *Event {
|
||||
return e.Ints("k", ints)
|
||||
},
|
||||
"Float": func(e *Event) *Event {
|
||||
return e.Float64("k", floats[0])
|
||||
},
|
||||
"Floats": func(e *Event) *Event {
|
||||
return e.Floats64("k", floats)
|
||||
},
|
||||
"Str": func(e *Event) *Event {
|
||||
return e.Str("k", strings[0])
|
||||
},
|
||||
"Strs": func(e *Event) *Event {
|
||||
return e.Strs("k", strings)
|
||||
},
|
||||
"Err": func(e *Event) *Event {
|
||||
return e.Err(errs[0])
|
||||
},
|
||||
"Errs": func(e *Event) *Event {
|
||||
return e.Errs("k", errs)
|
||||
},
|
||||
"Time": func(e *Event) *Event {
|
||||
return e.Time("k", times[0])
|
||||
},
|
||||
"Times": func(e *Event) *Event {
|
||||
return e.Times("k", times)
|
||||
},
|
||||
"Dur": func(e *Event) *Event {
|
||||
return e.Dur("k", durations[0])
|
||||
},
|
||||
"Durs": func(e *Event) *Event {
|
||||
return e.Durs("k", durations)
|
||||
},
|
||||
"Interface": func(e *Event) *Event {
|
||||
return e.Interface("k", o)
|
||||
},
|
||||
}
|
||||
logger := New(ioutil.Discard)
|
||||
b.ResetTimer()
|
||||
for name := range types {
|
||||
f := types[name]
|
||||
b.Run(name, func(b *testing.B) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
f(logger.Info()).Msg("")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+115
-1
@@ -12,6 +12,12 @@ func (c Context) Logger() Logger {
|
||||
return c.l
|
||||
}
|
||||
|
||||
// Fields is a helper function to use a map to set fields using type assertion.
|
||||
func (c Context) Fields(fields map[string]interface{}) Context {
|
||||
c.l.context = appendFields(c.l.context, fields)
|
||||
return c
|
||||
}
|
||||
|
||||
// Dict adds the field key with the dict to the logger context.
|
||||
func (c Context) Dict(key string, dict *Event) Context {
|
||||
dict.buf = append(dict.buf, '}')
|
||||
@@ -26,12 +32,30 @@ func (c Context) Str(key, val string) Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// Strs adds the field key with val as a string to the logger context.
|
||||
func (c Context) Strs(key string, vals []string) Context {
|
||||
c.l.context = appendStrings(c.l.context, key, vals)
|
||||
return c
|
||||
}
|
||||
|
||||
// Bytes adds the field key with val as a []byte to the logger context.
|
||||
func (c Context) Bytes(key string, val []byte) Context {
|
||||
c.l.context = appendBytes(c.l.context, key, val)
|
||||
return c
|
||||
}
|
||||
|
||||
// AnErr adds the field key with err as a string to the logger context.
|
||||
func (c Context) AnErr(key string, err error) Context {
|
||||
c.l.context = appendErrorKey(c.l.context, key, err)
|
||||
return c
|
||||
}
|
||||
|
||||
// Errs adds the field key with errs as an array of strings to the logger context.
|
||||
func (c Context) Errs(key string, errs []error) Context {
|
||||
c.l.context = appendErrorsKey(c.l.context, key, errs)
|
||||
return c
|
||||
}
|
||||
|
||||
// Err adds the field "error" with err as a string to the logger context.
|
||||
// To customize the key name, change zerolog.ErrorFieldName.
|
||||
func (c Context) Err(err error) Context {
|
||||
@@ -39,84 +63,162 @@ func (c Context) Err(err error) Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// Bool adds the field key with val as a Boolean to the logger context.
|
||||
// Bool adds the field key with val as a bool to the logger context.
|
||||
func (c Context) Bool(key string, b bool) Context {
|
||||
c.l.context = appendBool(c.l.context, key, b)
|
||||
return c
|
||||
}
|
||||
|
||||
// Bools adds the field key with val as a []bool to the logger context.
|
||||
func (c Context) Bools(key string, b []bool) Context {
|
||||
c.l.context = appendBools(c.l.context, key, b)
|
||||
return c
|
||||
}
|
||||
|
||||
// Int adds the field key with i as a int to the logger context.
|
||||
func (c Context) Int(key string, i int) Context {
|
||||
c.l.context = appendInt(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Ints adds the field key with i as a []int to the logger context.
|
||||
func (c Context) Ints(key string, i []int) Context {
|
||||
c.l.context = appendInts(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Int8 adds the field key with i as a int8 to the logger context.
|
||||
func (c Context) Int8(key string, i int8) Context {
|
||||
c.l.context = appendInt8(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Ints8 adds the field key with i as a []int8 to the logger context.
|
||||
func (c Context) Ints8(key string, i []int8) Context {
|
||||
c.l.context = appendInts8(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Int16 adds the field key with i as a int16 to the logger context.
|
||||
func (c Context) Int16(key string, i int16) Context {
|
||||
c.l.context = appendInt16(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Ints16 adds the field key with i as a []int16 to the logger context.
|
||||
func (c Context) Ints16(key string, i []int16) Context {
|
||||
c.l.context = appendInts16(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Int32 adds the field key with i as a int32 to the logger context.
|
||||
func (c Context) Int32(key string, i int32) Context {
|
||||
c.l.context = appendInt32(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Ints32 adds the field key with i as a []int32 to the logger context.
|
||||
func (c Context) Ints32(key string, i []int32) Context {
|
||||
c.l.context = appendInts32(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Int64 adds the field key with i as a int64 to the logger context.
|
||||
func (c Context) Int64(key string, i int64) Context {
|
||||
c.l.context = appendInt64(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Ints64 adds the field key with i as a []int64 to the logger context.
|
||||
func (c Context) Ints64(key string, i []int64) Context {
|
||||
c.l.context = appendInts64(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uint adds the field key with i as a uint to the logger context.
|
||||
func (c Context) Uint(key string, i uint) Context {
|
||||
c.l.context = appendUint(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uints adds the field key with i as a []uint to the logger context.
|
||||
func (c Context) Uints(key string, i []uint) Context {
|
||||
c.l.context = appendUints(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uint8 adds the field key with i as a uint8 to the logger context.
|
||||
func (c Context) Uint8(key string, i uint8) Context {
|
||||
c.l.context = appendUint8(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uints8 adds the field key with i as a []uint8 to the logger context.
|
||||
func (c Context) Uints8(key string, i []uint8) Context {
|
||||
c.l.context = appendUints8(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uint16 adds the field key with i as a uint16 to the logger context.
|
||||
func (c Context) Uint16(key string, i uint16) Context {
|
||||
c.l.context = appendUint16(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uints16 adds the field key with i as a []uint16 to the logger context.
|
||||
func (c Context) Uints16(key string, i []uint16) Context {
|
||||
c.l.context = appendUints16(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uint32 adds the field key with i as a uint32 to the logger context.
|
||||
func (c Context) Uint32(key string, i uint32) Context {
|
||||
c.l.context = appendUint32(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uints32 adds the field key with i as a []uint32 to the logger context.
|
||||
func (c Context) Uints32(key string, i []uint32) Context {
|
||||
c.l.context = appendUints32(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uint64 adds the field key with i as a uint64 to the logger context.
|
||||
func (c Context) Uint64(key string, i uint64) Context {
|
||||
c.l.context = appendUint64(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Uints64 adds the field key with i as a []uint64 to the logger context.
|
||||
func (c Context) Uints64(key string, i []uint64) Context {
|
||||
c.l.context = appendUints64(c.l.context, key, i)
|
||||
return c
|
||||
}
|
||||
|
||||
// Float32 adds the field key with f as a float32 to the logger context.
|
||||
func (c Context) Float32(key string, f float32) Context {
|
||||
c.l.context = appendFloat32(c.l.context, key, f)
|
||||
return c
|
||||
}
|
||||
|
||||
// Floats32 adds the field key with f as a []float32 to the logger context.
|
||||
func (c Context) Floats32(key string, f []float32) Context {
|
||||
c.l.context = appendFloats32(c.l.context, key, f)
|
||||
return c
|
||||
}
|
||||
|
||||
// Float64 adds the field key with f as a float64 to the logger context.
|
||||
func (c Context) Float64(key string, f float64) Context {
|
||||
c.l.context = appendFloat64(c.l.context, key, f)
|
||||
return c
|
||||
}
|
||||
|
||||
// Floats64 adds the field key with f as a []float64 to the logger context.
|
||||
func (c Context) Floats64(key string, f []float64) Context {
|
||||
c.l.context = appendFloats64(c.l.context, key, f)
|
||||
return c
|
||||
}
|
||||
|
||||
// Timestamp adds the current local time as UNIX timestamp to the logger context with the "time" key.
|
||||
// To customize the key name, change zerolog.TimestampFieldName.
|
||||
func (c Context) Timestamp() Context {
|
||||
@@ -134,12 +236,24 @@ func (c Context) Time(key string, t time.Time) Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// Times adds the field key with t formated as string using zerolog.TimeFieldFormat.
|
||||
func (c Context) Times(key string, t []time.Time) Context {
|
||||
c.l.context = appendTimes(c.l.context, key, t)
|
||||
return c
|
||||
}
|
||||
|
||||
// Dur adds the fields key with d divided by unit and stored as a float.
|
||||
func (c Context) Dur(key string, d time.Duration) Context {
|
||||
c.l.context = appendDuration(c.l.context, key, d)
|
||||
return c
|
||||
}
|
||||
|
||||
// Durs adds the fields key with d divided by unit and stored as a float.
|
||||
func (c Context) Durs(key string, d []time.Duration) Context {
|
||||
c.l.context = appendDurations(c.l.context, key, d)
|
||||
return c
|
||||
}
|
||||
|
||||
// Interface adds the field key with obj marshaled using reflection.
|
||||
func (c Context) Interface(key string, i interface{}) Context {
|
||||
c.l.context = appendInterface(c.l.context, key, i)
|
||||
|
||||
@@ -94,6 +94,15 @@ func (e *Event) Msgf(format string, v ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fields is a helper function to use a map to set fields using type assertion.
|
||||
func (e *Event) Fields(fields map[string]interface{}) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendFields(e.buf, fields)
|
||||
return e
|
||||
}
|
||||
|
||||
// Dict adds the field key with a dict to the event context.
|
||||
// Use zerolog.Dict() to create the dictionary.
|
||||
func (e *Event) Dict(key string, dict *Event) *Event {
|
||||
@@ -121,6 +130,24 @@ func (e *Event) Str(key, val string) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Strs adds the field key with vals as a []string to the *Event context.
|
||||
func (e *Event) Strs(key string, vals []string) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendStrings(e.buf, key, vals)
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes adds the field key with val as a []byte to the *Event context.
|
||||
func (e *Event) Bytes(key string, val []byte) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendBytes(e.buf, key, val)
|
||||
return e
|
||||
}
|
||||
|
||||
// AnErr adds the field key with err as a string to the *Event context.
|
||||
// If err is nil, no field is added.
|
||||
func (e *Event) AnErr(key string, err error) *Event {
|
||||
@@ -131,6 +158,16 @@ func (e *Event) AnErr(key string, err error) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Errs adds the field key with errs as an array of strings to the *Event context.
|
||||
// If err is nil, no field is added.
|
||||
func (e *Event) Errs(key string, errs []error) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendErrorsKey(e.buf, key, errs)
|
||||
return e
|
||||
}
|
||||
|
||||
// Err adds the field "error" with err as a string to the *Event context.
|
||||
// If err is nil, no field is added.
|
||||
// To customize the key name, change zerolog.ErrorFieldName.
|
||||
@@ -142,7 +179,7 @@ func (e *Event) Err(err error) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Bool adds the field key with val as a Boolean to the *Event context.
|
||||
// Bool adds the field key with val as a bool to the *Event context.
|
||||
func (e *Event) Bool(key string, b bool) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
@@ -151,6 +188,15 @@ func (e *Event) Bool(key string, b bool) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Bools adds the field key with val as a []bool to the *Event context.
|
||||
func (e *Event) Bools(key string, b []bool) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendBools(e.buf, key, b)
|
||||
return e
|
||||
}
|
||||
|
||||
// Int adds the field key with i as a int to the *Event context.
|
||||
func (e *Event) Int(key string, i int) *Event {
|
||||
if !e.enabled {
|
||||
@@ -160,6 +206,15 @@ func (e *Event) Int(key string, i int) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Ints adds the field key with i as a []int to the *Event context.
|
||||
func (e *Event) Ints(key string, i []int) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendInts(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Int8 adds the field key with i as a int8 to the *Event context.
|
||||
func (e *Event) Int8(key string, i int8) *Event {
|
||||
if !e.enabled {
|
||||
@@ -169,6 +224,15 @@ func (e *Event) Int8(key string, i int8) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Ints8 adds the field key with i as a []int8 to the *Event context.
|
||||
func (e *Event) Ints8(key string, i []int8) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendInts8(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Int16 adds the field key with i as a int16 to the *Event context.
|
||||
func (e *Event) Int16(key string, i int16) *Event {
|
||||
if !e.enabled {
|
||||
@@ -178,6 +242,15 @@ func (e *Event) Int16(key string, i int16) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Ints16 adds the field key with i as a []int16 to the *Event context.
|
||||
func (e *Event) Ints16(key string, i []int16) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendInts16(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Int32 adds the field key with i as a int32 to the *Event context.
|
||||
func (e *Event) Int32(key string, i int32) *Event {
|
||||
if !e.enabled {
|
||||
@@ -187,6 +260,15 @@ func (e *Event) Int32(key string, i int32) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Ints32 adds the field key with i as a []int32 to the *Event context.
|
||||
func (e *Event) Ints32(key string, i []int32) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendInts32(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Int64 adds the field key with i as a int64 to the *Event context.
|
||||
func (e *Event) Int64(key string, i int64) *Event {
|
||||
if !e.enabled {
|
||||
@@ -196,6 +278,15 @@ func (e *Event) Int64(key string, i int64) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Ints64 adds the field key with i as a []int64 to the *Event context.
|
||||
func (e *Event) Ints64(key string, i []int64) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendInts64(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Uint adds the field key with i as a uint to the *Event context.
|
||||
func (e *Event) Uint(key string, i uint) *Event {
|
||||
if !e.enabled {
|
||||
@@ -205,6 +296,15 @@ func (e *Event) Uint(key string, i uint) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Uints adds the field key with i as a []int to the *Event context.
|
||||
func (e *Event) Uints(key string, i []uint) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendUints(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Uint8 adds the field key with i as a uint8 to the *Event context.
|
||||
func (e *Event) Uint8(key string, i uint8) *Event {
|
||||
if !e.enabled {
|
||||
@@ -214,6 +314,15 @@ func (e *Event) Uint8(key string, i uint8) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Uints8 adds the field key with i as a []int8 to the *Event context.
|
||||
func (e *Event) Uints8(key string, i []uint8) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendUints8(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Uint16 adds the field key with i as a uint16 to the *Event context.
|
||||
func (e *Event) Uint16(key string, i uint16) *Event {
|
||||
if !e.enabled {
|
||||
@@ -223,6 +332,15 @@ func (e *Event) Uint16(key string, i uint16) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Uints16 adds the field key with i as a []int16 to the *Event context.
|
||||
func (e *Event) Uints16(key string, i []uint16) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendUints16(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Uint32 adds the field key with i as a uint32 to the *Event context.
|
||||
func (e *Event) Uint32(key string, i uint32) *Event {
|
||||
if !e.enabled {
|
||||
@@ -232,6 +350,15 @@ func (e *Event) Uint32(key string, i uint32) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Uints32 adds the field key with i as a []int32 to the *Event context.
|
||||
func (e *Event) Uints32(key string, i []uint32) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendUints32(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Uint64 adds the field key with i as a uint64 to the *Event context.
|
||||
func (e *Event) Uint64(key string, i uint64) *Event {
|
||||
if !e.enabled {
|
||||
@@ -241,6 +368,15 @@ func (e *Event) Uint64(key string, i uint64) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Uints64 adds the field key with i as a []int64 to the *Event context.
|
||||
func (e *Event) Uints64(key string, i []uint64) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendUints64(e.buf, key, i)
|
||||
return e
|
||||
}
|
||||
|
||||
// Float32 adds the field key with f as a float32 to the *Event context.
|
||||
func (e *Event) Float32(key string, f float32) *Event {
|
||||
if !e.enabled {
|
||||
@@ -250,6 +386,15 @@ func (e *Event) Float32(key string, f float32) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Floats32 adds the field key with f as a []float32 to the *Event context.
|
||||
func (e *Event) Floats32(key string, f []float32) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendFloats32(e.buf, key, f)
|
||||
return e
|
||||
}
|
||||
|
||||
// Float64 adds the field key with f as a float64 to the *Event context.
|
||||
func (e *Event) Float64(key string, f float64) *Event {
|
||||
if !e.enabled {
|
||||
@@ -259,6 +404,15 @@ func (e *Event) Float64(key string, f float64) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Floats64 adds the field key with f as a []float64 to the *Event context.
|
||||
func (e *Event) Floats64(key string, f []float64) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendFloats64(e.buf, key, f)
|
||||
return e
|
||||
}
|
||||
|
||||
// Timestamp adds the current local time as UNIX timestamp to the *Event context with the "time" key.
|
||||
// To customize the key name, change zerolog.TimestampFieldName.
|
||||
func (e *Event) Timestamp() *Event {
|
||||
@@ -278,6 +432,15 @@ func (e *Event) Time(key string, t time.Time) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Times adds the field key with t formated as string using zerolog.TimeFieldFormat.
|
||||
func (e *Event) Times(key string, t []time.Time) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendTimes(e.buf, key, t)
|
||||
return e
|
||||
}
|
||||
|
||||
// Dur adds the field key with duration d stored as zerolog.DurationFieldUnit.
|
||||
// If zerolog.DurationFieldInteger is true, durations are rendered as integer
|
||||
// instead of float.
|
||||
@@ -289,6 +452,17 @@ func (e *Event) Dur(key string, d time.Duration) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// Durs adds the field key with duration d stored as zerolog.DurationFieldUnit.
|
||||
// If zerolog.DurationFieldInteger is true, durations are rendered as integer
|
||||
// instead of float.
|
||||
func (e *Event) Durs(key string, d []time.Duration) *Event {
|
||||
if !e.enabled {
|
||||
return e
|
||||
}
|
||||
e.buf = appendDurations(e.buf, key, d)
|
||||
return e
|
||||
}
|
||||
|
||||
// TimeDiff adds the field key with positive duration between time t and start.
|
||||
// If time t is not greater than start, duration will be 0.
|
||||
// Duration format follows the same principle as Dur().
|
||||
|
||||
@@ -3,10 +3,99 @@ package zerolog
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func appendFields(dst []byte, fields map[string]interface{}) []byte {
|
||||
keys := make([]string, 0, len(fields))
|
||||
for key, _ := range fields {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
switch val := fields[key].(type) {
|
||||
case string:
|
||||
dst = appendString(dst, key, val)
|
||||
case []byte:
|
||||
dst = appendBytes(dst, key, val)
|
||||
case error:
|
||||
dst = appendErrorKey(dst, key, val)
|
||||
case []error:
|
||||
dst = appendErrorsKey(dst, key, val)
|
||||
case bool:
|
||||
dst = appendBool(dst, key, val)
|
||||
case int:
|
||||
dst = appendInt(dst, key, val)
|
||||
case int8:
|
||||
dst = appendInt8(dst, key, val)
|
||||
case int16:
|
||||
dst = appendInt16(dst, key, val)
|
||||
case int32:
|
||||
dst = appendInt32(dst, key, val)
|
||||
case int64:
|
||||
dst = appendInt64(dst, key, val)
|
||||
case uint:
|
||||
dst = appendUint(dst, key, val)
|
||||
case uint8:
|
||||
dst = appendUint8(dst, key, val)
|
||||
case uint16:
|
||||
dst = appendUint16(dst, key, val)
|
||||
case uint32:
|
||||
dst = appendUint32(dst, key, val)
|
||||
case uint64:
|
||||
dst = appendUint64(dst, key, val)
|
||||
case float32:
|
||||
dst = appendFloat32(dst, key, val)
|
||||
case float64:
|
||||
dst = appendFloat64(dst, key, val)
|
||||
case time.Time:
|
||||
dst = appendTime(dst, key, val)
|
||||
case time.Duration:
|
||||
dst = appendDuration(dst, key, val)
|
||||
case []string:
|
||||
dst = appendStrings(dst, key, val)
|
||||
case []bool:
|
||||
dst = appendBools(dst, key, val)
|
||||
case []int:
|
||||
dst = appendInts(dst, key, val)
|
||||
case []int8:
|
||||
dst = appendInts8(dst, key, val)
|
||||
case []int16:
|
||||
dst = appendInts16(dst, key, val)
|
||||
case []int32:
|
||||
dst = appendInts32(dst, key, val)
|
||||
case []int64:
|
||||
dst = appendInts64(dst, key, val)
|
||||
case []uint:
|
||||
dst = appendUints(dst, key, val)
|
||||
// case []uint8:
|
||||
// dst = appendUints8(dst, key, val)
|
||||
case []uint16:
|
||||
dst = appendUints16(dst, key, val)
|
||||
case []uint32:
|
||||
dst = appendUints32(dst, key, val)
|
||||
case []uint64:
|
||||
dst = appendUints64(dst, key, val)
|
||||
case []float32:
|
||||
dst = appendFloats32(dst, key, val)
|
||||
case []float64:
|
||||
dst = appendFloats64(dst, key, val)
|
||||
case []time.Time:
|
||||
dst = appendTimes(dst, key, val)
|
||||
case []time.Duration:
|
||||
dst = appendDurations(dst, key, val)
|
||||
case nil:
|
||||
dst = append(appendKey(dst, key), "null"...)
|
||||
default:
|
||||
dst = appendInterface(dst, key, val)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendKey(dst []byte, key string) []byte {
|
||||
if len(dst) > 1 {
|
||||
dst = append(dst, ',')
|
||||
@@ -19,6 +108,25 @@ func appendString(dst []byte, key, val string) []byte {
|
||||
return appendJSONString(appendKey(dst, key), val)
|
||||
}
|
||||
|
||||
func appendStrings(dst []byte, key string, vals []string) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = appendJSONString(dst, vals[0])
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = appendJSONString(append(dst, ','), val)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendBytes(dst []byte, key string, val []byte) []byte {
|
||||
return appendJSONBytes(appendKey(dst, key), val)
|
||||
}
|
||||
|
||||
func appendErrorKey(dst []byte, key string, err error) []byte {
|
||||
if err == nil {
|
||||
return dst
|
||||
@@ -26,7 +134,33 @@ func appendErrorKey(dst []byte, key string, err error) []byte {
|
||||
return appendJSONString(appendKey(dst, key), err.Error())
|
||||
}
|
||||
|
||||
func appendErrorsKey(dst []byte, key string, errs []error) []byte {
|
||||
if len(errs) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
if errs[0] != nil {
|
||||
dst = appendJSONString(dst, errs[0].Error())
|
||||
} else {
|
||||
dst = append(dst, "null"...)
|
||||
}
|
||||
if len(errs) > 1 {
|
||||
for _, err := range errs[1:] {
|
||||
if err == nil {
|
||||
dst = append(dst, ",null"...)
|
||||
continue
|
||||
}
|
||||
dst = appendJSONString(append(dst, ','), err.Error())
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendError(dst []byte, err error) []byte {
|
||||
if err == nil {
|
||||
return dst
|
||||
}
|
||||
return appendErrorKey(dst, ErrorFieldName, err)
|
||||
}
|
||||
|
||||
@@ -34,52 +168,262 @@ func appendBool(dst []byte, key string, val bool) []byte {
|
||||
return strconv.AppendBool(appendKey(dst, key), val)
|
||||
}
|
||||
|
||||
func appendBools(dst []byte, key string, vals []bool) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendBool(dst, vals[0])
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendBool(append(dst, ','), val)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInt(dst []byte, key string, val int) []byte {
|
||||
return strconv.AppendInt(appendKey(dst, key), int64(val), 10)
|
||||
}
|
||||
|
||||
func appendInts(dst []byte, key string, vals []int) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, int64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInt8(dst []byte, key string, val int8) []byte {
|
||||
return strconv.AppendInt(appendKey(dst, key), int64(val), 10)
|
||||
}
|
||||
|
||||
func appendInts8(dst []byte, key string, vals []int8) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, int64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInt16(dst []byte, key string, val int16) []byte {
|
||||
return strconv.AppendInt(appendKey(dst, key), int64(val), 10)
|
||||
}
|
||||
|
||||
func appendInts16(dst []byte, key string, vals []int16) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, int64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInt32(dst []byte, key string, val int32) []byte {
|
||||
return strconv.AppendInt(appendKey(dst, key), int64(val), 10)
|
||||
}
|
||||
|
||||
func appendInts32(dst []byte, key string, vals []int32) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, int64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), int64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInt64(dst []byte, key string, val int64) []byte {
|
||||
return strconv.AppendInt(appendKey(dst, key), int64(val), 10)
|
||||
return strconv.AppendInt(appendKey(dst, key), val, 10)
|
||||
}
|
||||
|
||||
func appendInts64(dst []byte, key string, vals []int64) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, vals[0], 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), val, 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint(dst []byte, key string, val uint) []byte {
|
||||
return strconv.AppendUint(appendKey(dst, key), uint64(val), 10)
|
||||
}
|
||||
|
||||
func appendUints(dst []byte, key string, vals []uint) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint8(dst []byte, key string, val uint8) []byte {
|
||||
return strconv.AppendUint(appendKey(dst, key), uint64(val), 10)
|
||||
}
|
||||
|
||||
func appendUints8(dst []byte, key string, vals []uint8) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint16(dst []byte, key string, val uint16) []byte {
|
||||
return strconv.AppendUint(appendKey(dst, key), uint64(val), 10)
|
||||
}
|
||||
|
||||
func appendUints16(dst []byte, key string, vals []uint16) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint32(dst []byte, key string, val uint32) []byte {
|
||||
return strconv.AppendUint(appendKey(dst, key), uint64(val), 10)
|
||||
}
|
||||
|
||||
func appendUints32(dst []byte, key string, vals []uint32) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendUint(dst, uint64(vals[0]), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendUint(append(dst, ','), uint64(val), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint64(dst []byte, key string, val uint64) []byte {
|
||||
return strconv.AppendUint(appendKey(dst, key), uint64(val), 10)
|
||||
}
|
||||
|
||||
func appendUints64(dst []byte, key string, vals []uint64) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendUint(dst, vals[0], 10)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = strconv.AppendUint(append(dst, ','), val, 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendFloat(dst []byte, val float64, bitSize int) []byte {
|
||||
// JSON does not permit NaN or Infinity. A typical JSON encoder would fail
|
||||
// with an error, but a logging library wants the data to get thru so we
|
||||
// make a tradeoff and store those types as string.
|
||||
switch {
|
||||
case math.IsNaN(val):
|
||||
return append(dst, `"NaN"`...)
|
||||
case math.IsInf(val, 1):
|
||||
return append(dst, `"+Inf"`...)
|
||||
case math.IsInf(val, -1):
|
||||
return append(dst, `"-Inf"`...)
|
||||
}
|
||||
return strconv.AppendFloat(dst, val, 'f', -1, bitSize)
|
||||
}
|
||||
|
||||
func appendFloat32(dst []byte, key string, val float32) []byte {
|
||||
return strconv.AppendFloat(appendKey(dst, key), float64(val), 'f', -1, 32)
|
||||
return appendFloat(appendKey(dst, key), float64(val), 32)
|
||||
}
|
||||
|
||||
func appendFloats32(dst []byte, key string, vals []float32) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = appendFloat(dst, float64(vals[0]), 32)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = appendFloat(append(dst, ','), float64(val), 32)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendFloat64(dst []byte, key string, val float64) []byte {
|
||||
return strconv.AppendFloat(appendKey(dst, key), float64(val), 'f', -1, 32)
|
||||
return appendFloat(appendKey(dst, key), val, 64)
|
||||
}
|
||||
|
||||
func appendFloats64(dst []byte, key string, vals []float64) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = appendFloat(dst, vals[0], 32)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = appendFloat(append(dst, ','), val, 64)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendTime(dst []byte, key string, t time.Time) []byte {
|
||||
@@ -89,6 +433,39 @@ func appendTime(dst []byte, key string, t time.Time) []byte {
|
||||
return append(t.AppendFormat(append(appendKey(dst, key), '"'), TimeFieldFormat), '"')
|
||||
}
|
||||
|
||||
func appendTimes(dst []byte, key string, vals []time.Time) []byte {
|
||||
if TimeFieldFormat == "" {
|
||||
return appendUnixTimes(dst, key, vals)
|
||||
}
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = append(vals[0].AppendFormat(append(dst, '"'), TimeFieldFormat), '"')
|
||||
if len(vals) > 1 {
|
||||
for _, t := range vals[1:] {
|
||||
dst = append(t.AppendFormat(append(dst, ',', '"'), TimeFieldFormat), '"')
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUnixTimes(dst []byte, key string, vals []time.Time) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, vals[0].Unix(), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, t := range vals[1:] {
|
||||
dst = strconv.AppendInt(dst, t.Unix(), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendTimestamp(dst []byte) []byte {
|
||||
return appendTime(dst, TimestampFieldName, TimestampFunc())
|
||||
}
|
||||
@@ -100,6 +477,39 @@ func appendDuration(dst []byte, key string, d time.Duration) []byte {
|
||||
return appendFloat64(dst, key, float64(d)/float64(DurationFieldUnit))
|
||||
}
|
||||
|
||||
func appendDurations(dst []byte, key string, vals []time.Duration) []byte {
|
||||
if DurationFieldInteger {
|
||||
return appendIntDurations(dst, key, vals)
|
||||
}
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendFloat(dst, float64(vals[0])/float64(DurationFieldUnit), 'f', -1, 32)
|
||||
if len(vals) > 1 {
|
||||
for _, d := range vals[1:] {
|
||||
dst = strconv.AppendFloat(append(dst, ','), float64(d)/float64(DurationFieldUnit), 'f', -1, 32)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendIntDurations(dst []byte, key string, vals []time.Duration) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(appendKey(dst, key), '[', ']')
|
||||
}
|
||||
dst = append(appendKey(dst, key), '[')
|
||||
dst = strconv.AppendInt(dst, int64(vals[0]/DurationFieldUnit), 10)
|
||||
if len(vals) > 1 {
|
||||
for _, d := range vals[1:] {
|
||||
dst = strconv.AppendInt(append(dst, ','), int64(d/DurationFieldUnit), 10)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendInterface(dst []byte, key string, i interface{}) []byte {
|
||||
marshaled, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_appendFloat64(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input float64
|
||||
want []byte
|
||||
}{
|
||||
{"-Inf", math.Inf(-1), []byte(`"foo":"-Inf"`)},
|
||||
{"+Inf", math.Inf(1), []byte(`"foo":"+Inf"`)},
|
||||
{"NaN", math.NaN(), []byte(`"foo":"NaN"`)},
|
||||
{"0", 0, []byte(`"foo":0`)},
|
||||
{"-1.1", -1.1, []byte(`"foo":-1.1`)},
|
||||
{"1e20", 1e20, []byte(`"foo":100000000000000000000`)},
|
||||
{"1e21", 1e21, []byte(`"foo":1000000000000000000000`)},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := appendFloat32([]byte{}, "foo", float32(tt.input)); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("appendFloat32() = %s, want %s", got, tt.want)
|
||||
}
|
||||
if got := appendFloat64([]byte{}, "foo", tt.input); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("appendFloat32() = %s, want %s", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -63,5 +63,5 @@ func DisableSampling(v bool) {
|
||||
}
|
||||
|
||||
func samplingDisabled() bool {
|
||||
return atomic.LoadUint32(gLevel) == 1
|
||||
return atomic.LoadUint32(disableSampling) == 1
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/rs/xid"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/zenazn/goji/web/mutil"
|
||||
)
|
||||
|
||||
// FromRequest gets the logger in the request's context.
|
||||
@@ -152,3 +154,15 @@ func RequestIDHandler(fieldKey, headerName string) func(next http.Handler) http.
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
lw := mutil.WrapWriter(w)
|
||||
next.ServeHTTP(lw, r)
|
||||
f(r, lw.Status(), lw.BytesWritten(), time.Since(start))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,3 +94,72 @@ func appendJSONStringComplex(dst []byte, s string, i int) []byte {
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// appendJSONBytes is a mirror of appendJSONString with []byte arg
|
||||
func appendJSONBytes(dst, s []byte) []byte {
|
||||
dst = append(dst, '"')
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] < 0x20 || s[i] > 0x7e || s[i] == '\\' || s[i] == '"' {
|
||||
dst = appendJSONBytesComplex(dst, s, i)
|
||||
return append(dst, '"')
|
||||
}
|
||||
}
|
||||
dst = append(dst, s...)
|
||||
return append(dst, '"')
|
||||
}
|
||||
|
||||
// appendJSONBytesComplex is a mirror of the appendJSONStringComplex
|
||||
// with []byte arg
|
||||
func appendJSONBytesComplex(dst, s []byte, i int) []byte {
|
||||
start := 0
|
||||
for i < len(s) {
|
||||
b := s[i]
|
||||
if b >= utf8.RuneSelf {
|
||||
r, size := utf8.DecodeRune(s[i:])
|
||||
if r == utf8.RuneError && size == 1 {
|
||||
if start < i {
|
||||
dst = append(dst, s[start:i]...)
|
||||
}
|
||||
dst = append(dst, `\ufffd`...)
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
i += size
|
||||
continue
|
||||
}
|
||||
if b >= 0x20 && b <= 0x7e && b != '\\' && b != '"' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// We encountered a character that needs to be encoded.
|
||||
// Let's append the previous simple characters to the byte slice
|
||||
// and switch our operation to read and encode the remainder
|
||||
// characters byte-by-byte.
|
||||
if start < i {
|
||||
dst = append(dst, s[start:i]...)
|
||||
}
|
||||
switch b {
|
||||
case '"', '\\':
|
||||
dst = append(dst, '\\', b)
|
||||
case '\b':
|
||||
dst = append(dst, '\\', 'b')
|
||||
case '\f':
|
||||
dst = append(dst, '\\', 'f')
|
||||
case '\n':
|
||||
dst = append(dst, '\\', 'n')
|
||||
case '\r':
|
||||
dst = append(dst, '\\', 'r')
|
||||
case '\t':
|
||||
dst = append(dst, '\\', 't')
|
||||
default:
|
||||
dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
}
|
||||
if start < len(s) {
|
||||
dst = append(dst, s[start:]...)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
+116
-48
@@ -2,57 +2,58 @@ package zerolog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func TestAppendJSONString(t *testing.T) {
|
||||
encodeStringTests := []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"", `""`},
|
||||
{"\\", `"\\"`},
|
||||
{"\x00", `"\u0000"`},
|
||||
{"\x01", `"\u0001"`},
|
||||
{"\x02", `"\u0002"`},
|
||||
{"\x03", `"\u0003"`},
|
||||
{"\x04", `"\u0004"`},
|
||||
{"\x05", `"\u0005"`},
|
||||
{"\x06", `"\u0006"`},
|
||||
{"\x07", `"\u0007"`},
|
||||
{"\x08", `"\b"`},
|
||||
{"\x09", `"\t"`},
|
||||
{"\x0a", `"\n"`},
|
||||
{"\x0b", `"\u000b"`},
|
||||
{"\x0c", `"\f"`},
|
||||
{"\x0d", `"\r"`},
|
||||
{"\x0e", `"\u000e"`},
|
||||
{"\x0f", `"\u000f"`},
|
||||
{"\x10", `"\u0010"`},
|
||||
{"\x11", `"\u0011"`},
|
||||
{"\x12", `"\u0012"`},
|
||||
{"\x13", `"\u0013"`},
|
||||
{"\x14", `"\u0014"`},
|
||||
{"\x15", `"\u0015"`},
|
||||
{"\x16", `"\u0016"`},
|
||||
{"\x17", `"\u0017"`},
|
||||
{"\x18", `"\u0018"`},
|
||||
{"\x19", `"\u0019"`},
|
||||
{"\x1a", `"\u001a"`},
|
||||
{"\x1b", `"\u001b"`},
|
||||
{"\x1c", `"\u001c"`},
|
||||
{"\x1d", `"\u001d"`},
|
||||
{"\x1e", `"\u001e"`},
|
||||
{"\x1f", `"\u001f"`},
|
||||
{"✭", `"✭"`},
|
||||
{"foo\xc2\x7fbar", `"foo\ufffd\u007fbar"`}, // invalid sequence
|
||||
{"ascii", `"ascii"`},
|
||||
{"\"a", `"\"a"`},
|
||||
{"\x1fa", `"\u001fa"`},
|
||||
{"foo\"bar\"baz", `"foo\"bar\"baz"`},
|
||||
{"\x1ffoo\x1fbar\x1fbaz", `"\u001ffoo\u001fbar\u001fbaz"`},
|
||||
{"emoji \u2764\ufe0f!", `"emoji ❤️!"`},
|
||||
}
|
||||
var encodeStringTests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"", `""`},
|
||||
{"\\", `"\\"`},
|
||||
{"\x00", `"\u0000"`},
|
||||
{"\x01", `"\u0001"`},
|
||||
{"\x02", `"\u0002"`},
|
||||
{"\x03", `"\u0003"`},
|
||||
{"\x04", `"\u0004"`},
|
||||
{"\x05", `"\u0005"`},
|
||||
{"\x06", `"\u0006"`},
|
||||
{"\x07", `"\u0007"`},
|
||||
{"\x08", `"\b"`},
|
||||
{"\x09", `"\t"`},
|
||||
{"\x0a", `"\n"`},
|
||||
{"\x0b", `"\u000b"`},
|
||||
{"\x0c", `"\f"`},
|
||||
{"\x0d", `"\r"`},
|
||||
{"\x0e", `"\u000e"`},
|
||||
{"\x0f", `"\u000f"`},
|
||||
{"\x10", `"\u0010"`},
|
||||
{"\x11", `"\u0011"`},
|
||||
{"\x12", `"\u0012"`},
|
||||
{"\x13", `"\u0013"`},
|
||||
{"\x14", `"\u0014"`},
|
||||
{"\x15", `"\u0015"`},
|
||||
{"\x16", `"\u0016"`},
|
||||
{"\x17", `"\u0017"`},
|
||||
{"\x18", `"\u0018"`},
|
||||
{"\x19", `"\u0019"`},
|
||||
{"\x1a", `"\u001a"`},
|
||||
{"\x1b", `"\u001b"`},
|
||||
{"\x1c", `"\u001c"`},
|
||||
{"\x1d", `"\u001d"`},
|
||||
{"\x1e", `"\u001e"`},
|
||||
{"\x1f", `"\u001f"`},
|
||||
{"✭", `"✭"`},
|
||||
{"foo\xc2\x7fbar", `"foo\ufffd\u007fbar"`}, // invalid sequence
|
||||
{"ascii", `"ascii"`},
|
||||
{"\"a", `"\"a"`},
|
||||
{"\x1fa", `"\u001fa"`},
|
||||
{"foo\"bar\"baz", `"foo\"bar\"baz"`},
|
||||
{"\x1ffoo\x1fbar\x1fbaz", `"\u001ffoo\u001fbar\u001fbaz"`},
|
||||
{"emoji \u2764\ufe0f!", `"emoji ❤️!"`},
|
||||
}
|
||||
|
||||
func TestAppendJSONString(t *testing.T) {
|
||||
for _, tt := range encodeStringTests {
|
||||
b := appendJSONString([]byte{}, tt.in)
|
||||
if got, want := string(b), tt.out; got != want {
|
||||
@@ -61,6 +62,52 @@ func TestAppendJSONString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendJSONBytes(t *testing.T) {
|
||||
for _, tt := range encodeStringTests {
|
||||
b := appendJSONBytes([]byte{}, []byte(tt.in))
|
||||
if got, want := string(b), tt.out; got != want {
|
||||
t.Errorf("appendJSONBytes(%q) = %#q, want %#q", tt.in, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test that encodeState.stringBytes and encodeState.string use the same encoding.
|
||||
var r []rune
|
||||
for i := '\u0000'; i <= unicode.MaxRune; i++ {
|
||||
r = append(r, i)
|
||||
}
|
||||
s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
|
||||
|
||||
enc := string(appendJSONString([]byte{}, s))
|
||||
encBytes := string(appendJSONBytes([]byte{}, []byte(s)))
|
||||
|
||||
if enc != encBytes {
|
||||
i := 0
|
||||
for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
|
||||
i++
|
||||
}
|
||||
enc = enc[i:]
|
||||
encBytes = encBytes[i:]
|
||||
i = 0
|
||||
for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
|
||||
i++
|
||||
}
|
||||
enc = enc[:len(enc)-i]
|
||||
encBytes = encBytes[:len(encBytes)-i]
|
||||
|
||||
if len(enc) > 20 {
|
||||
enc = enc[:20] + "..."
|
||||
}
|
||||
if len(encBytes) > 20 {
|
||||
encBytes = encBytes[:20] + "..."
|
||||
}
|
||||
|
||||
t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendJSONString(b *testing.B) {
|
||||
tests := map[string]string{
|
||||
"NoEncoding": `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
@@ -80,3 +127,24 @@ func BenchmarkAppendJSONString(b *testing.B) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAppendJSONBytes(b *testing.B) {
|
||||
tests := map[string]string{
|
||||
"NoEncoding": `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
"EncodingFirst": `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
"EncodingMiddle": `aaaaaaaaaaaaaaaaaaaaaaaaa"aaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
"EncodingLast": `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`,
|
||||
"MultiBytesFirst": `❤️aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
"MultiBytesMiddle": `aaaaaaaaaaaaaaaaaaaaaaaaa❤️aaaaaaaaaaaaaaaaaaaaaaaa`,
|
||||
"MultiBytesLast": `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa❤️`,
|
||||
}
|
||||
for name, str := range tests {
|
||||
byt := []byte(str)
|
||||
b.Run(name, func(b *testing.B) {
|
||||
buf := make([]byte, 0, 100)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = appendJSONBytes(buf, byt)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@@ -246,6 +247,30 @@ func (l Logger) Panic() *Event {
|
||||
return l.newEvent(PanicLevel, true, func(msg string) { panic(msg) })
|
||||
}
|
||||
|
||||
// WithLevel starts a new message with level.
|
||||
//
|
||||
// You must call Msg on the returned event in order to send the event.
|
||||
func (l Logger) WithLevel(level Level) *Event {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return l.Debug()
|
||||
case InfoLevel:
|
||||
return l.Info()
|
||||
case WarnLevel:
|
||||
return l.Warn()
|
||||
case ErrorLevel:
|
||||
return l.Error()
|
||||
case FatalLevel:
|
||||
return l.Fatal()
|
||||
case PanicLevel:
|
||||
return l.Panic()
|
||||
case Disabled:
|
||||
return disabledEvent
|
||||
default:
|
||||
panic("zerolog: WithLevel(): invalid level: " + strconv.Itoa(int(level)))
|
||||
}
|
||||
}
|
||||
|
||||
// Log starts a new message with no level. Setting GlobalLevel to Disabled
|
||||
// will still disable events produced by this method.
|
||||
//
|
||||
|
||||
@@ -91,6 +91,15 @@ func ExampleLogger_Error() {
|
||||
// Output: {"level":"error","error":"some error","message":"error doing something"}
|
||||
}
|
||||
|
||||
func ExampleLogger_WithLevel() {
|
||||
log := zerolog.New(os.Stdout)
|
||||
|
||||
log.WithLevel(zerolog.InfoLevel).
|
||||
Msg("hello world")
|
||||
|
||||
// Output: {"level":"info","message":"hello world"}
|
||||
}
|
||||
|
||||
func ExampleLogger_Write() {
|
||||
log := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar").
|
||||
@@ -159,6 +168,22 @@ func ExampleEvent_Dur() {
|
||||
// Output: {"foo":"bar","dur":10000,"message":"hello world"}
|
||||
}
|
||||
|
||||
func ExampleEvent_Durs() {
|
||||
d := []time.Duration{
|
||||
time.Duration(10 * time.Second),
|
||||
time.Duration(20 * time.Second),
|
||||
}
|
||||
|
||||
log := zerolog.New(os.Stdout)
|
||||
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Durs("durs", d).
|
||||
Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","durs":[10000,20000],"message":"hello world"}
|
||||
}
|
||||
|
||||
func ExampleContext_Dict() {
|
||||
log := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar").
|
||||
@@ -201,3 +226,19 @@ func ExampleContext_Dur() {
|
||||
|
||||
// Output: {"foo":"bar","dur":10000,"message":"hello world"}
|
||||
}
|
||||
|
||||
func ExampleContext_Durs() {
|
||||
d := []time.Duration{
|
||||
time.Duration(10 * time.Second),
|
||||
time.Duration(20 * time.Second),
|
||||
}
|
||||
|
||||
log := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar").
|
||||
Durs("durs", d).
|
||||
Logger()
|
||||
|
||||
log.Log().Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","durs":[10000,20000],"message":"hello world"}
|
||||
}
|
||||
|
||||
+144
-21
@@ -14,7 +14,7 @@ func TestLog(t *testing.T) {
|
||||
log := New(out)
|
||||
log.Log().Msg("")
|
||||
if got, want := out.String(), "{}\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestLog(t *testing.T) {
|
||||
log := New(out)
|
||||
log.Log().Str("foo", "bar").Msg("")
|
||||
if got, want := out.String(), `{"foo":"bar"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestLog(t *testing.T) {
|
||||
Int("n", 123).
|
||||
Msg("")
|
||||
if got, want := out.String(), `{"foo":"bar","n":123}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func TestInfo(t *testing.T) {
|
||||
log := New(out)
|
||||
log.Info().Msg("")
|
||||
if got, want := out.String(), `{"level":"info"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestInfo(t *testing.T) {
|
||||
log := New(out)
|
||||
log.Info().Str("foo", "bar").Msg("")
|
||||
if got, want := out.String(), `{"level":"info","foo":"bar"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestInfo(t *testing.T) {
|
||||
Int("n", 123).
|
||||
Msg("")
|
||||
if got, want := out.String(), `{"level":"info","foo":"bar","n":123}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -95,15 +95,46 @@ func TestWith(t *testing.T) {
|
||||
Logger()
|
||||
log.Log().Msg("")
|
||||
if got, want := out.String(), `{"foo":"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,"time":"0001-01-01T00:00:00Z"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", 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),
|
||||
"dur": 1 * time.Second,
|
||||
"time": time.Time{},
|
||||
}).Msg("")
|
||||
if got, want := out.String(), `{"bool":true,"bytes":"bar","dur":1000,"error":"some error","float32":11,"float64":12,"int":1,"int16":3,"int32":4,"int64":5,"int8":2,"nil":null,"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 TestFields(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
log := New(out)
|
||||
now := time.Now()
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Str("string", "foo").
|
||||
Bytes("bytes", []byte("bar")).
|
||||
AnErr("some_err", nil).
|
||||
Err(errors.New("some error")).
|
||||
Bool("bool", true).
|
||||
@@ -121,18 +152,101 @@ func TestFields(t *testing.T) {
|
||||
Float64("float64", 12).
|
||||
Dur("dur", 1*time.Second).
|
||||
Time("time", time.Time{}).
|
||||
TimeDiff("diff", time.Now(), time.Now().Add(-10*time.Second)).
|
||||
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
||||
Msg("")
|
||||
if got, want := out.String(), `{"foo":"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,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
if got, want := out.String(), `{"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,"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 := out.String(), `{"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{time.Time{}}).
|
||||
Msg("")
|
||||
if got, want := out.String(), `{"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{time.Time{}, time.Time{}}).
|
||||
Msg("")
|
||||
if got, want := out.String(), `{"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("foo", "bar").
|
||||
Str("string", "foo").
|
||||
Bytes("bytes", []byte("bar")).
|
||||
AnErr("some_err", nil).
|
||||
Err(errors.New("some error")).
|
||||
Bool("bool", true).
|
||||
@@ -150,10 +264,10 @@ func TestFieldsDisabled(t *testing.T) {
|
||||
Float64("float64", 12).
|
||||
Dur("dur", 1*time.Second).
|
||||
Time("time", time.Time{}).
|
||||
TimeDiff("diff", time.Now(), time.Now().Add(-10*time.Second)).
|
||||
TimeDiff("diff", now, now.Add(-10*time.Second)).
|
||||
Msg("")
|
||||
if got, want := out.String(), ""; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +275,7 @@ func TestMsgf(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
New(out).Log().Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
|
||||
if got, want := out.String(), `{"message":"one two 3.4 5 six"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +284,7 @@ func TestWithAndFieldsCombined(t *testing.T) {
|
||||
log := New(out).With().Str("f1", "val").Str("f2", "val").Logger()
|
||||
log.Log().Str("f3", "val").Msg("")
|
||||
if got, want := out.String(), `{"f1":"val","f2":"val","f3":"val"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +294,7 @@ func TestLevel(t *testing.T) {
|
||||
log := New(out).Level(Disabled)
|
||||
log.Info().Msg("test")
|
||||
if got, want := out.String(), ""; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -189,7 +303,7 @@ func TestLevel(t *testing.T) {
|
||||
log := New(out).Level(InfoLevel)
|
||||
log.Info().Msg("test")
|
||||
if got, want := out.String(), `{"level":"info","message":"test"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -202,7 +316,7 @@ func TestSampling(t *testing.T) {
|
||||
log.Log().Int("i", 3).Msg("")
|
||||
log.Log().Int("i", 4).Msg("")
|
||||
if got, want := out.String(), "{\"sample\":2,\"i\":2}\n{\"sample\":2,\"i\":4}\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +351,11 @@ func TestLevelWriter(t *testing.T) {
|
||||
log.Info().Msg("2")
|
||||
log.Warn().Msg("3")
|
||||
log.Error().Msg("4")
|
||||
log.WithLevel(DebugLevel).Msg("5")
|
||||
log.WithLevel(InfoLevel).Msg("6")
|
||||
log.WithLevel(WarnLevel).Msg("7")
|
||||
log.WithLevel(ErrorLevel).Msg("8")
|
||||
|
||||
want := []struct {
|
||||
l Level
|
||||
p string
|
||||
@@ -245,6 +364,10 @@ func TestLevelWriter(t *testing.T) {
|
||||
{InfoLevel, `{"level":"info","message":"2"}` + "\n"},
|
||||
{WarnLevel, `{"level":"warn","message":"3"}` + "\n"},
|
||||
{ErrorLevel, `{"level":"error","message":"4"}` + "\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"},
|
||||
}
|
||||
if got := lw.ops; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("invalid ops:\ngot:\n%v\nwant:\n%v", got, want)
|
||||
@@ -263,7 +386,7 @@ func TestContextTimestamp(t *testing.T) {
|
||||
log.Log().Msg("hello world")
|
||||
|
||||
if got, want := out.String(), `{"time":"2001-02-03T04:05:06Z","foo":"bar","message":"hello world"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +402,6 @@ func TestEventTimestamp(t *testing.T) {
|
||||
log.Log().Timestamp().Msg("hello world")
|
||||
|
||||
if got, want := out.String(), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output: got %q, want %q", got, want)
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user