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

Compare commits

...

2 Commits

Author SHA1 Message Date
Olivier Poitrey f220d89e1f Add more benchmarks 2017-07-25 17:25:40 -07:00
Olivier Poitrey 87aceba511 Handle special values like Inf and NaN gracefuly 2017-07-25 16:55:47 -07:00
3 changed files with 144 additions and 6 deletions
+86
View File
@@ -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("")
}
})
})
}
}
+25 -6
View File
@@ -3,6 +3,7 @@ package zerolog
import (
"encoding/json"
"fmt"
"math"
"sort"
"strconv"
"time"
@@ -157,6 +158,9 @@ func appendErrorsKey(dst []byte, key string, errs []error) []byte {
}
func appendError(dst []byte, err error) []byte {
if err == nil {
return dst
}
return appendErrorKey(dst, ErrorFieldName, err)
}
@@ -369,8 +373,23 @@ func appendUints64(dst []byte, key string, vals []uint64) []byte {
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 {
@@ -378,10 +397,10 @@ func appendFloats32(dst []byte, key string, vals []float32) []byte {
return append(appendKey(dst, key), '[', ']')
}
dst = append(appendKey(dst, key), '[')
dst = strconv.AppendFloat(dst, float64(vals[0]), 'f', -1, 32)
dst = appendFloat(dst, float64(vals[0]), 32)
if len(vals) > 1 {
for _, val := range vals[1:] {
dst = strconv.AppendFloat(append(dst, ','), float64(val), 'f', -1, 32)
dst = appendFloat(append(dst, ','), float64(val), 32)
}
}
dst = append(dst, ']')
@@ -389,7 +408,7 @@ func appendFloats32(dst []byte, key string, vals []float32) []byte {
}
func appendFloat64(dst []byte, key string, val float64) []byte {
return strconv.AppendFloat(appendKey(dst, key), val, 'f', -1, 32)
return appendFloat(appendKey(dst, key), val, 64)
}
func appendFloats64(dst []byte, key string, vals []float64) []byte {
@@ -397,10 +416,10 @@ func appendFloats64(dst []byte, key string, vals []float64) []byte {
return append(appendKey(dst, key), '[', ']')
}
dst = append(appendKey(dst, key), '[')
dst = strconv.AppendFloat(dst, vals[0], 'f', -1, 32)
dst = appendFloat(dst, vals[0], 32)
if len(vals) > 1 {
for _, val := range vals[1:] {
dst = strconv.AppendFloat(append(dst, ','), val, 'f', -1, 32)
dst = appendFloat(append(dst, ','), val, 64)
}
}
dst = append(dst, ']')
+33
View File
@@ -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)
}
})
}
}