mirror of https://github.com/rs/zerolog.git
Allow setting floating point precision in JSON. (#663)
This commit is contained in:
parent
e5aa7e3627
commit
7d9db06a53
|
@ -642,6 +642,10 @@ Some settings can be changed and will be applied to all loggers:
|
|||
* `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
|
||||
* `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`).
|
||||
* `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
|
||||
* `zerolog.FloatingPointPrecision`: If set to a value other than -1, controls the number
|
||||
of digits when formatting float numbers in JSON. See
|
||||
[strconv.FormatFloat](https://pkg.go.dev/strconv#FormatFloat)
|
||||
for more details.
|
||||
|
||||
## Field Types
|
||||
|
||||
|
|
6
array.go
6
array.go
|
@ -183,13 +183,13 @@ func (a *Array) Uint64(i uint64) *Array {
|
|||
|
||||
// Float32 appends f as a float32 to the array.
|
||||
func (a *Array) Float32(f float32) *Array {
|
||||
a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f)
|
||||
a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
|
||||
return a
|
||||
}
|
||||
|
||||
// Float64 appends f as a float64 to the array.
|
||||
func (a *Array) Float64(f float64) *Array {
|
||||
a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f)
|
||||
a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
|
||||
return a
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ func (a *Array) Time(t time.Time) *Array {
|
|||
|
||||
// Dur appends d to the array.
|
||||
func (a *Array) Dur(d time.Duration) *Array {
|
||||
a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger)
|
||||
a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
return a
|
||||
}
|
||||
|
||||
|
|
12
context.go
12
context.go
|
@ -325,25 +325,25 @@ func (c Context) Uints64(key string, i []uint64) Context {
|
|||
|
||||
// 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 = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f)
|
||||
c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
|
||||
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 = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f)
|
||||
c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
|
||||
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 = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f)
|
||||
c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
|
||||
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 = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f)
|
||||
c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
|
||||
return c
|
||||
}
|
||||
|
||||
|
@ -379,13 +379,13 @@ func (c Context) Times(key string, t []time.Time) Context {
|
|||
|
||||
// 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 = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
|
||||
c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
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 = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
|
||||
c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
return c
|
||||
}
|
||||
|
||||
|
|
12
encoder.go
12
encoder.go
|
@ -13,13 +13,13 @@ type encoder interface {
|
|||
AppendBool(dst []byte, val bool) []byte
|
||||
AppendBools(dst []byte, vals []bool) []byte
|
||||
AppendBytes(dst, s []byte) []byte
|
||||
AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte
|
||||
AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte
|
||||
AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte
|
||||
AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte
|
||||
AppendEndMarker(dst []byte) []byte
|
||||
AppendFloat32(dst []byte, val float32) []byte
|
||||
AppendFloat64(dst []byte, val float64) []byte
|
||||
AppendFloats32(dst []byte, vals []float32) []byte
|
||||
AppendFloats64(dst []byte, vals []float64) []byte
|
||||
AppendFloat32(dst []byte, val float32, precision int) []byte
|
||||
AppendFloat64(dst []byte, val float64, precision int) []byte
|
||||
AppendFloats32(dst []byte, vals []float32, precision int) []byte
|
||||
AppendFloats64(dst []byte, vals []float64, precision int) []byte
|
||||
AppendHex(dst, s []byte) []byte
|
||||
AppendIPAddr(dst []byte, ip net.IP) []byte
|
||||
AppendIPPrefix(dst []byte, pfx net.IPNet) []byte
|
||||
|
|
14
event.go
14
event.go
|
@ -644,7 +644,7 @@ func (e *Event) Float32(key string, f float32) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f)
|
||||
e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -653,7 +653,7 @@ func (e *Event) Floats32(key string, f []float32) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f)
|
||||
e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ func (e *Event) Float64(key string, f float64) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f)
|
||||
e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -671,7 +671,7 @@ func (e *Event) Floats64(key string, f []float64) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f)
|
||||
e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -713,7 +713,7 @@ func (e *Event) Dur(key string, d time.Duration) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
|
||||
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -724,7 +724,7 @@ func (e *Event) Durs(key string, d []time.Duration) *Event {
|
|||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
|
||||
e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -739,7 +739,7 @@ func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event {
|
|||
if t.After(start) {
|
||||
d = t.Sub(start)
|
||||
}
|
||||
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
|
||||
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
return e
|
||||
}
|
||||
|
||||
|
|
18
fields.go
18
fields.go
|
@ -139,13 +139,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
|||
case uint64:
|
||||
dst = enc.AppendUint64(dst, val)
|
||||
case float32:
|
||||
dst = enc.AppendFloat32(dst, val)
|
||||
dst = enc.AppendFloat32(dst, val, FloatingPointPrecision)
|
||||
case float64:
|
||||
dst = enc.AppendFloat64(dst, val)
|
||||
dst = enc.AppendFloat64(dst, val, FloatingPointPrecision)
|
||||
case time.Time:
|
||||
dst = enc.AppendTime(dst, val, TimeFieldFormat)
|
||||
case time.Duration:
|
||||
dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger)
|
||||
dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
case *string:
|
||||
if val != nil {
|
||||
dst = enc.AppendString(dst, *val)
|
||||
|
@ -220,13 +220,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
|||
}
|
||||
case *float32:
|
||||
if val != nil {
|
||||
dst = enc.AppendFloat32(dst, *val)
|
||||
dst = enc.AppendFloat32(dst, *val, FloatingPointPrecision)
|
||||
} else {
|
||||
dst = enc.AppendNil(dst)
|
||||
}
|
||||
case *float64:
|
||||
if val != nil {
|
||||
dst = enc.AppendFloat64(dst, *val)
|
||||
dst = enc.AppendFloat64(dst, *val, FloatingPointPrecision)
|
||||
} else {
|
||||
dst = enc.AppendNil(dst)
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
|||
}
|
||||
case *time.Duration:
|
||||
if val != nil {
|
||||
dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger)
|
||||
dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
} else {
|
||||
dst = enc.AppendNil(dst)
|
||||
}
|
||||
|
@ -267,13 +267,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
|||
case []uint64:
|
||||
dst = enc.AppendUints64(dst, val)
|
||||
case []float32:
|
||||
dst = enc.AppendFloats32(dst, val)
|
||||
dst = enc.AppendFloats32(dst, val, FloatingPointPrecision)
|
||||
case []float64:
|
||||
dst = enc.AppendFloats64(dst, val)
|
||||
dst = enc.AppendFloats64(dst, val, FloatingPointPrecision)
|
||||
case []time.Time:
|
||||
dst = enc.AppendTimes(dst, val, TimeFieldFormat)
|
||||
case []time.Duration:
|
||||
dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger)
|
||||
dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
|
||||
case nil:
|
||||
dst = enc.AppendNil(dst)
|
||||
case net.IP:
|
||||
|
|
|
@ -151,6 +151,11 @@ var (
|
|||
// TriggerLevelWriterBufferReuseLimit is a limit in bytes that a buffer is dropped
|
||||
// from the TriggerLevelWriter buffer pool if the buffer grows above the limit.
|
||||
TriggerLevelWriterBufferReuseLimit = 64 * 1024
|
||||
|
||||
// FloatingPointPrecision, if set to a value other than -1, controls the number
|
||||
// of digits when formatting float numbers in JSON. See strconv.FormatFloat for
|
||||
// more details.
|
||||
FloatingPointPrecision = -1
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -29,7 +29,7 @@ func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte {
|
|||
nanos := t.Nanosecond()
|
||||
var val float64
|
||||
val = float64(secs)*1.0 + float64(nanos)*1e-9
|
||||
return e.AppendFloat64(dst, val)
|
||||
return e.AppendFloat64(dst, val, -1)
|
||||
}
|
||||
|
||||
// AppendTime encodes and adds a timestamp to the dst byte array.
|
||||
|
@ -64,17 +64,17 @@ func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte
|
|||
// AppendDuration encodes and adds a duration to the dst byte array.
|
||||
// useInt field indicates whether to store the duration as seconds (integer) or
|
||||
// as seconds+nanoseconds (float).
|
||||
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
|
||||
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, unused int) []byte {
|
||||
if useInt {
|
||||
return e.AppendInt64(dst, int64(d/unit))
|
||||
}
|
||||
return e.AppendFloat64(dst, float64(d)/float64(unit))
|
||||
return e.AppendFloat64(dst, float64(d)/float64(unit), unused)
|
||||
}
|
||||
|
||||
// AppendDurations encodes and adds an array of durations to the dst byte array.
|
||||
// useInt field indicates whether to store the duration as seconds (integer) or
|
||||
// as seconds+nanoseconds (float).
|
||||
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte {
|
||||
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, unused int) []byte {
|
||||
major := majorTypeArray
|
||||
l := len(vals)
|
||||
if l == 0 {
|
||||
|
@ -87,7 +87,7 @@ func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Dur
|
|||
dst = appendCborTypePrefix(dst, major, uint64(l))
|
||||
}
|
||||
for _, d := range vals {
|
||||
dst = e.AppendDuration(dst, d, unit, useInt)
|
||||
dst = e.AppendDuration(dst, d, unit, useInt, unused)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
|
|||
}
|
||||
|
||||
// AppendFloat32 encodes and inserts a single precision float value into the dst byte array.
|
||||
func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
|
||||
func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte {
|
||||
switch {
|
||||
case math.IsNaN(float64(val)):
|
||||
return append(dst, "\xfa\x7f\xc0\x00\x00"...)
|
||||
|
@ -372,7 +372,7 @@ func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
|
|||
}
|
||||
|
||||
// AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array.
|
||||
func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
|
||||
func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) []byte {
|
||||
major := majorTypeArray
|
||||
l := len(vals)
|
||||
if l == 0 {
|
||||
|
@ -385,13 +385,13 @@ func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
|
|||
dst = appendCborTypePrefix(dst, major, uint64(l))
|
||||
}
|
||||
for _, v := range vals {
|
||||
dst = e.AppendFloat32(dst, v)
|
||||
dst = e.AppendFloat32(dst, v, unused)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// AppendFloat64 encodes and inserts a double precision float value into the dst byte array.
|
||||
func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
|
||||
func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte {
|
||||
switch {
|
||||
case math.IsNaN(val):
|
||||
return append(dst, "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"...)
|
||||
|
@ -412,7 +412,7 @@ func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
|
|||
}
|
||||
|
||||
// AppendFloats64 encodes and inserts an array of double precision float values into the dst byte array.
|
||||
func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
|
||||
func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) []byte {
|
||||
major := majorTypeArray
|
||||
l := len(vals)
|
||||
if l == 0 {
|
||||
|
@ -425,7 +425,7 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
|
|||
dst = appendCborTypePrefix(dst, major, uint64(l))
|
||||
}
|
||||
for _, v := range vals {
|
||||
dst = e.AppendFloat64(dst, v)
|
||||
dst = e.AppendFloat64(dst, v, unused)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ var float32TestCases = []struct {
|
|||
|
||||
func TestAppendFloat32(t *testing.T) {
|
||||
for _, tc := range float32TestCases {
|
||||
s := enc.AppendFloat32([]byte{}, tc.val)
|
||||
s := enc.AppendFloat32([]byte{}, tc.val, -1)
|
||||
got := string(s)
|
||||
if got != tc.binary {
|
||||
t.Errorf("AppendFloat32(%f)=0x%s, want: 0x%s",
|
||||
|
@ -306,9 +306,9 @@ func BenchmarkAppendFloat(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
switch str.sz {
|
||||
case 4:
|
||||
_ = enc.AppendFloat32(buf, float32(str.val))
|
||||
_ = enc.AppendFloat32(buf, float32(str.val), -1)
|
||||
case 8:
|
||||
_ = enc.AppendFloat64(buf, str.val)
|
||||
_ = enc.AppendFloat64(buf, str.val, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -88,24 +88,24 @@ func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte {
|
|||
|
||||
// AppendDuration formats the input duration with the given unit & format
|
||||
// and appends the encoded string to the input byte slice.
|
||||
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
|
||||
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte {
|
||||
if useInt {
|
||||
return strconv.AppendInt(dst, int64(d/unit), 10)
|
||||
}
|
||||
return e.AppendFloat64(dst, float64(d)/float64(unit))
|
||||
return e.AppendFloat64(dst, float64(d)/float64(unit), precision)
|
||||
}
|
||||
|
||||
// AppendDurations formats the input durations with the given unit & format
|
||||
// and appends the encoded string list to the input byte slice.
|
||||
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte {
|
||||
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(dst, '[', ']')
|
||||
}
|
||||
dst = append(dst, '[')
|
||||
dst = e.AppendDuration(dst, vals[0], unit, useInt)
|
||||
dst = e.AppendDuration(dst, vals[0], unit, useInt, precision)
|
||||
if len(vals) > 1 {
|
||||
for _, d := range vals[1:] {
|
||||
dst = e.AppendDuration(append(dst, ','), d, unit, useInt)
|
||||
dst = e.AppendDuration(append(dst, ','), d, unit, useInt, precision)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
|
|
|
@ -299,7 +299,7 @@ func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
|
|||
return dst
|
||||
}
|
||||
|
||||
func appendFloat(dst []byte, val float64, bitSize int) []byte {
|
||||
func appendFloat(dst []byte, val float64, bitSize, precision 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 through so we
|
||||
// make a tradeoff and store those types as string.
|
||||
|
@ -314,13 +314,16 @@ func appendFloat(dst []byte, val float64, bitSize int) []byte {
|
|||
// convert as if by es6 number to string conversion
|
||||
// see also https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/encoding/json/encode.go;l=573
|
||||
strFmt := byte('f')
|
||||
// Use float32 comparisons for underlying float32 value to get precise cutoffs right.
|
||||
if abs := math.Abs(val); abs != 0 {
|
||||
if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
|
||||
strFmt = 'e'
|
||||
// If precision is set to a value other than -1, we always just format the float using that precision.
|
||||
if precision == -1 {
|
||||
// Use float32 comparisons for underlying float32 value to get precise cutoffs right.
|
||||
if abs := math.Abs(val); abs != 0 {
|
||||
if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
|
||||
strFmt = 'e'
|
||||
}
|
||||
}
|
||||
}
|
||||
dst = strconv.AppendFloat(dst, val, strFmt, -1, bitSize)
|
||||
dst = strconv.AppendFloat(dst, val, strFmt, precision, bitSize)
|
||||
if strFmt == 'e' {
|
||||
// Clean up e-09 to e-9
|
||||
n := len(dst)
|
||||
|
@ -334,21 +337,21 @@ func appendFloat(dst []byte, val float64, bitSize int) []byte {
|
|||
|
||||
// AppendFloat32 converts the input float32 to a string and
|
||||
// appends the encoded string to the input byte slice.
|
||||
func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
|
||||
return appendFloat(dst, float64(val), 32)
|
||||
func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []byte {
|
||||
return appendFloat(dst, float64(val), 32, precision)
|
||||
}
|
||||
|
||||
// AppendFloats32 encodes the input float32s to json and
|
||||
// appends the encoded string list to the input byte slice.
|
||||
func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
|
||||
func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(dst, '[', ']')
|
||||
}
|
||||
dst = append(dst, '[')
|
||||
dst = appendFloat(dst, float64(vals[0]), 32)
|
||||
dst = appendFloat(dst, float64(vals[0]), 32, precision)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = appendFloat(append(dst, ','), float64(val), 32)
|
||||
dst = appendFloat(append(dst, ','), float64(val), 32, precision)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
|
@ -357,21 +360,21 @@ func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
|
|||
|
||||
// AppendFloat64 converts the input float64 to a string and
|
||||
// appends the encoded string to the input byte slice.
|
||||
func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
|
||||
return appendFloat(dst, val, 64)
|
||||
func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []byte {
|
||||
return appendFloat(dst, val, 64, precision)
|
||||
}
|
||||
|
||||
// AppendFloats64 encodes the input float64s to json and
|
||||
// appends the encoded string list to the input byte slice.
|
||||
func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
|
||||
func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int) []byte {
|
||||
if len(vals) == 0 {
|
||||
return append(dst, '[', ']')
|
||||
}
|
||||
dst = append(dst, '[')
|
||||
dst = appendFloat(dst, vals[0], 64)
|
||||
dst = appendFloat(dst, vals[0], 64, precision)
|
||||
if len(vals) > 1 {
|
||||
for _, val := range vals[1:] {
|
||||
dst = appendFloat(append(dst, ','), val, 64)
|
||||
dst = appendFloat(append(dst, ','), val, 64, precision)
|
||||
}
|
||||
}
|
||||
dst = append(dst, ']')
|
||||
|
|
|
@ -11,18 +11,20 @@ import (
|
|||
|
||||
func TestAppendType(t *testing.T) {
|
||||
w := map[string]func(interface{}) []byte{
|
||||
"AppendInt": func(v interface{}) []byte { return enc.AppendInt([]byte{}, v.(int)) },
|
||||
"AppendInt8": func(v interface{}) []byte { return enc.AppendInt8([]byte{}, v.(int8)) },
|
||||
"AppendInt16": func(v interface{}) []byte { return enc.AppendInt16([]byte{}, v.(int16)) },
|
||||
"AppendInt32": func(v interface{}) []byte { return enc.AppendInt32([]byte{}, v.(int32)) },
|
||||
"AppendInt64": func(v interface{}) []byte { return enc.AppendInt64([]byte{}, v.(int64)) },
|
||||
"AppendUint": func(v interface{}) []byte { return enc.AppendUint([]byte{}, v.(uint)) },
|
||||
"AppendUint8": func(v interface{}) []byte { return enc.AppendUint8([]byte{}, v.(uint8)) },
|
||||
"AppendUint16": func(v interface{}) []byte { return enc.AppendUint16([]byte{}, v.(uint16)) },
|
||||
"AppendUint32": func(v interface{}) []byte { return enc.AppendUint32([]byte{}, v.(uint32)) },
|
||||
"AppendUint64": func(v interface{}) []byte { return enc.AppendUint64([]byte{}, v.(uint64)) },
|
||||
"AppendFloat32": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32)) },
|
||||
"AppendFloat64": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64)) },
|
||||
"AppendInt": func(v interface{}) []byte { return enc.AppendInt([]byte{}, v.(int)) },
|
||||
"AppendInt8": func(v interface{}) []byte { return enc.AppendInt8([]byte{}, v.(int8)) },
|
||||
"AppendInt16": func(v interface{}) []byte { return enc.AppendInt16([]byte{}, v.(int16)) },
|
||||
"AppendInt32": func(v interface{}) []byte { return enc.AppendInt32([]byte{}, v.(int32)) },
|
||||
"AppendInt64": func(v interface{}) []byte { return enc.AppendInt64([]byte{}, v.(int64)) },
|
||||
"AppendUint": func(v interface{}) []byte { return enc.AppendUint([]byte{}, v.(uint)) },
|
||||
"AppendUint8": func(v interface{}) []byte { return enc.AppendUint8([]byte{}, v.(uint8)) },
|
||||
"AppendUint16": func(v interface{}) []byte { return enc.AppendUint16([]byte{}, v.(uint16)) },
|
||||
"AppendUint32": func(v interface{}) []byte { return enc.AppendUint32([]byte{}, v.(uint32)) },
|
||||
"AppendUint64": func(v interface{}) []byte { return enc.AppendUint64([]byte{}, v.(uint64)) },
|
||||
"AppendFloat32": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32), -1) },
|
||||
"AppendFloat64": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64), -1) },
|
||||
"AppendFloat32SmallPrecision": func(v interface{}) []byte { return enc.AppendFloat32([]byte{}, v.(float32), 1) },
|
||||
"AppendFloat64SmallPrecision": func(v interface{}) []byte { return enc.AppendFloat64([]byte{}, v.(float64), 1) },
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -55,6 +57,9 @@ func TestAppendType(t *testing.T) {
|
|||
{"AppendFloat64(-1.1)", "AppendFloat64", float64(-1.1), []byte(`-1.1`)},
|
||||
{"AppendFloat64(1e20)", "AppendFloat64", float64(1e20), []byte(`100000000000000000000`)},
|
||||
{"AppendFloat64(1e21)", "AppendFloat64", float64(1e21), []byte(`1e+21`)},
|
||||
|
||||
{"AppendFloat32SmallPrecision(-1.123)", "AppendFloat32SmallPrecision", float32(-1.123), []byte(`-1.1`)},
|
||||
{"AppendFloat64SmallPrecision(-1.123)", "AppendFloat64SmallPrecision", float64(-1.123), []byte(`-1.1`)},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -301,7 +306,7 @@ func TestEncoder_AppendFloat64(t *testing.T) {
|
|||
for _, tc := range float64Tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
var b []byte
|
||||
b = (Encoder{}).AppendFloat64(b, tc.Val)
|
||||
b = (Encoder{}).AppendFloat64(b, tc.Val, -1)
|
||||
if s := string(b); tc.Want != s {
|
||||
t.Errorf("%q", s)
|
||||
}
|
||||
|
@ -314,7 +319,7 @@ func FuzzEncoder_AppendFloat64(f *testing.F) {
|
|||
f.Add(tc.Val)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, val float64) {
|
||||
actual := (Encoder{}).AppendFloat64(nil, val)
|
||||
actual := (Encoder{}).AppendFloat64(nil, val, -1)
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("empty buffer")
|
||||
}
|
||||
|
@ -447,7 +452,7 @@ func TestEncoder_AppendFloat32(t *testing.T) {
|
|||
for _, tc := range float32Tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
var b []byte
|
||||
b = (Encoder{}).AppendFloat32(b, tc.Val)
|
||||
b = (Encoder{}).AppendFloat32(b, tc.Val, -1)
|
||||
if s := string(b); tc.Want != s {
|
||||
t.Errorf("%q", s)
|
||||
}
|
||||
|
@ -460,7 +465,7 @@ func FuzzEncoder_AppendFloat32(f *testing.F) {
|
|||
f.Add(tc.Val)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, val float32) {
|
||||
actual := (Encoder{}).AppendFloat32(nil, val)
|
||||
actual := (Encoder{}).AppendFloat32(nil, val, -1)
|
||||
if len(actual) == 0 {
|
||||
t.Fatal("empty buffer")
|
||||
}
|
||||
|
@ -528,7 +533,7 @@ func BenchmarkEncoder_AppendFloat32(b *testing.B) {
|
|||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, f := range floats {
|
||||
dst = (Encoder{}).AppendFloat32(dst[:0], f)
|
||||
dst = (Encoder{}).AppendFloat32(dst[:0], f, -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -542,7 +547,7 @@ func BenchmarkEncoder_AppendFloat64(b *testing.B) {
|
|||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, f := range floats {
|
||||
dst = (Encoder{}).AppendFloat64(dst[:0], f)
|
||||
dst = (Encoder{}).AppendFloat64(dst[:0], f, -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue