From 3e85c4b21c1adb254dd43a93d93263fbe7d9dc13 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Fri, 19 Apr 2019 15:48:31 -0700 Subject: [PATCH] Add a new time format for UNIX timestamp in milliseconds --- README.md | 17 ++++++++--------- benchmark_test.go | 2 +- globals.go | 16 +++++++++++++--- internal/json/time.go | 31 +++++++++++++++++++++++++++++-- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index eefc1f6..5429b13 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ func main() { // UNIX Time is faster and smaller than most timestamps // If you set zerolog.TimeFieldFormat to an empty string, // logs will write with UNIX time - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Print("hello world") } @@ -76,7 +76,7 @@ import ( ) func main() { - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Debug(). Str("Scale", "833 cents"). @@ -102,7 +102,7 @@ import ( ) func main() { - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Info().Msg("hello world") } @@ -138,7 +138,7 @@ import ( ) func main() { - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix debug := flag.Bool("debug", false, "sets log level to debug") flag.Parse() @@ -189,7 +189,7 @@ import ( ) func main() { - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Log(). Str("foo", "bar"). @@ -215,7 +215,7 @@ func main() { err := errors.New("A repo man spends his life getting into tense situations") service := "myservice" - zerolog.TimeFieldFormat = "" + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Fatal(). Err(err). @@ -474,9 +474,8 @@ Some settings can be changed and will by applied to all loggers: * `zerolog.LevelFieldName`: Can be set to customize level field name. * `zerolog.MessageFieldName`: Can be set to customize message field name. * `zerolog.ErrorFieldName`: Can be set to customize `Err` field name. -* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with an empty string, times are formated as UNIX timestamp. - // DurationFieldUnit defines the unit for time.Duration type fields added - // using the Dur method. +* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix` or `zerolog.TimeFormatUnixMs`, times are formated as UNIX timestamp. +* DurationFieldUnit defines the unit for time.Duration type fields added using the Dur method. * `DurationFieldUnit`: Sets the unit of the fields added by `Dur` (default: `time.Millisecond`). * `DurationFieldInteger`: If set to true, `Dur` fields are formatted as integers instead of floats. * `ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking. diff --git a/benchmark_test.go b/benchmark_test.go index 4ae9d49..84e7370 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -234,7 +234,7 @@ func BenchmarkLogFieldType(b *testing.B) { func BenchmarkContextFieldType(b *testing.B) { oldFormat := TimeFieldFormat - TimeFieldFormat = "" + TimeFieldFormat = TimeFormatUnix defer func() { TimeFieldFormat = oldFormat }() bools := []bool{true, false, true, false, true, false, true, false, true, false} ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} diff --git a/globals.go b/globals.go index 2024137..c1fa37c 100644 --- a/globals.go +++ b/globals.go @@ -6,6 +6,16 @@ import ( ) import "sync/atomic" +const ( + // TimeFormatUnix defines a time format that makes time fields to be + // serialized as Unix timestamp integers. + TimeFormatUnix = "" + + // TimeFormatUnix defines a time format that makes time fields to be + // serialized as Unix timestamp integers in milliseconds. + TimeFormatUnixMs = "UNIXMS" +) + var ( // TimestampFieldName is the field name used for the timestamp field. TimestampFieldName = "time" @@ -46,9 +56,9 @@ var ( return err } - // TimeFieldFormat defines the time format of the Time field type. - // If set to an empty string, the time is formatted as an UNIX timestamp - // as integer. + // TimeFieldFormat defines the time format of the Time field type. If set to + // TimeFormatUnix or TimeFormatUnixMs, the time is formatted as an UNIX + // timestamp as integer. TimeFieldFormat = time.RFC3339 // TimestampFunc defines the function called to generate a timestamp. diff --git a/internal/json/time.go b/internal/json/time.go index 739afff..18dea5e 100644 --- a/internal/json/time.go +++ b/internal/json/time.go @@ -5,11 +5,20 @@ import ( "time" ) +const ( + // Import from zerolog/global.go + timeFormatUnix = "" + timeFormatUnixMs = "UNIXMS" +) + // AppendTime formats the input time with the given format // and appends the encoded string to the input byte slice. func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte { - if format == "" { + switch format { + case timeFormatUnix: return e.AppendInt64(dst, t.Unix()) + case timeFormatUnixMs: + return e.AppendInt64(dst, t.UnixNano()/1000000) } return append(t.AppendFormat(append(dst, '"'), format), '"') } @@ -17,8 +26,11 @@ func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte { // AppendTimes converts the input times with the given format // and appends the encoded string list to the input byte slice. func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte { - if format == "" { + switch format { + case timeFormatUnix: return appendUnixTimes(dst, vals) + case timeFormatUnixMs: + return appendUnixMsTimes(dst, vals) } if len(vals) == 0 { return append(dst, '[', ']') @@ -49,6 +61,21 @@ func appendUnixTimes(dst []byte, vals []time.Time) []byte { return dst } +func appendUnixMsTimes(dst []byte, vals []time.Time) []byte { + if len(vals) == 0 { + return append(dst, '[', ']') + } + dst = append(dst, '[') + dst = strconv.AppendInt(dst, vals[0].UnixNano()/1000000, 10) + if len(vals) > 1 { + for _, t := range vals[1:] { + dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/1000000, 10) + } + } + dst = append(dst, ']') + return dst +} + // AppendDuration formats the input duration with the given unit & format // and appends the encoded string to the input byte slice. func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {