From 52639a7d4f10c2c59d6c455485c14cd51b1d9ebe Mon Sep 17 00:00:00 2001 From: tmshn Date: Sat, 1 Sep 2018 02:04:21 +0900 Subject: [PATCH 01/10] Added zapcore.TimeEncoderOfFormat --- zapcore/encoder.go | 17 +++++++++++++++-- zapcore/encoder_test.go | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index f0509522b..9245b3a09 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -21,6 +21,7 @@ package zapcore import ( + "strings" "time" "go.uber.org/zap/buffer" @@ -115,17 +116,29 @@ func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { enc.AppendString(t.Format("2006-01-02T15:04:05.000Z0700")) } +// TimeEncoderOfFormat returns TimeEncoder which serializes a time.Time using +// given format. +func TimeEncoderOfFormat(format string) TimeEncoder { + return func(t time.Time, enc PrimitiveArrayEncoder) { + enc.AppendString(t.Format(format)) + } +} + // UnmarshalText unmarshals text to a TimeEncoder. "iso8601" and "ISO8601" are // unmarshaled to ISO8601TimeEncoder, "millis" is unmarshaled to -// EpochMillisTimeEncoder, and anything else is unmarshaled to EpochTimeEncoder. +// EpochMillisTimeEncoder, "format=*" is unmarshaled to TimeEncoder with given +// format, and anything else is unmarshaled to EpochTimeEncoder. func (e *TimeEncoder) UnmarshalText(text []byte) error { - switch string(text) { + vals := strings.SplitAfterN(string(text), "=", 2) + switch vals[0] { case "iso8601", "ISO8601": *e = ISO8601TimeEncoder case "millis": *e = EpochMillisTimeEncoder case "nanos": *e = EpochNanosTimeEncoder + case "format=": + *e = TimeEncoderOfFormat(vals[1]) default: *e = EpochTimeEncoder } diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 04641678c..ffe25d8ef 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -538,6 +538,7 @@ func TestTimeEncoders(t *testing.T) { {"ISO8601", "1970-01-01T00:01:40.050Z"}, {"millis", 100050.005}, {"nanos", int64(100050005000)}, + {"format=06/01/02 03:04pm", "70/01/01 12:01am"}, {"", 100.050005}, {"something-random", 100.050005}, } From 7de11fd01e01b3954997c70a6a6730f9725cd0c9 Mon Sep 17 00:00:00 2001 From: Shinichi TAMURA Date: Fri, 19 Jun 2020 00:22:17 +0900 Subject: [PATCH 02/10] use encodeTimeLayout --- zapcore/encoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index 93b7518bf..f04620b9d 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -156,7 +156,7 @@ func RFC3339NanoTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { // given format. func TimeEncoderOfFormat(format string) TimeEncoder { return func(t time.Time, enc PrimitiveArrayEncoder) { - enc.AppendString(t.Format(format)) + encodeTimeLayout(t, format, enc) } } From d2a9484d1f9dc6468e623110b15f77dd1f4d5c2a Mon Sep 17 00:00:00 2001 From: Shinichi TAMURA Date: Fri, 19 Jun 2020 00:24:31 +0900 Subject: [PATCH 03/10] Fix docs to clarify the usage --- zapcore/encoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index f04620b9d..5de779c03 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -166,7 +166,7 @@ func TimeEncoderOfFormat(format string) TimeEncoder { // "iso8601" and "ISO8601" are unmarshaled to ISO8601TimeEncoder. // "millis" is unmarshaled to EpochMillisTimeEncoder. // "nanos" is unmarshaled to EpochNanosEncoder. -// "format=*" is unmarshaled to TimeEncoder with given format. +// "format=" is unmarshaled to TimeEncoder with given format. // Anything else is unmarshaled to EpochTimeEncoder. func (e *TimeEncoder) UnmarshalText(text []byte) error { vals := strings.SplitAfterN(string(text), "=", 2) From dce7a8b395d21bfc93bbf45afe2341f813b3106e Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Sat, 20 Jun 2020 18:34:43 +0900 Subject: [PATCH 04/10] rename: TimeEncoderOfFormat -> TimeEncoderOfLayout --- zapcore/encoder.go | 14 +++++++------- zapcore/encoder_test.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index 5de779c03..bcc858c3b 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -152,11 +152,11 @@ func RFC3339NanoTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { encodeTimeLayout(t, time.RFC3339Nano, enc) } -// TimeEncoderOfFormat returns TimeEncoder which serializes a time.Time using -// given format. -func TimeEncoderOfFormat(format string) TimeEncoder { +// TimeEncoderOfLayout returns TimeEncoder which serializes a time.Time using +// given layout. +func TimeEncoderOfLayout(layout string) TimeEncoder { return func(t time.Time, enc PrimitiveArrayEncoder) { - encodeTimeLayout(t, format, enc) + encodeTimeLayout(t, layout, enc) } } @@ -166,7 +166,7 @@ func TimeEncoderOfFormat(format string) TimeEncoder { // "iso8601" and "ISO8601" are unmarshaled to ISO8601TimeEncoder. // "millis" is unmarshaled to EpochMillisTimeEncoder. // "nanos" is unmarshaled to EpochNanosEncoder. -// "format=" is unmarshaled to TimeEncoder with given format. +// "layout=" is unmarshaled to TimeEncoder with given layout. // Anything else is unmarshaled to EpochTimeEncoder. func (e *TimeEncoder) UnmarshalText(text []byte) error { vals := strings.SplitAfterN(string(text), "=", 2) @@ -181,8 +181,8 @@ func (e *TimeEncoder) UnmarshalText(text []byte) error { *e = EpochMillisTimeEncoder case "nanos": *e = EpochNanosTimeEncoder - case "format=": - *e = TimeEncoderOfFormat(vals[1]) + case "layout=": + *e = TimeEncoderOfLayout(vals[1]) default: *e = EpochTimeEncoder } diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 7aa3017df..baa97500f 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -530,7 +530,7 @@ func TestTimeEncoders(t *testing.T) { {"ISO8601", "1970-01-01T00:01:40.050Z"}, {"millis", 100050.005}, {"nanos", int64(100050005000)}, - {"format=06/01/02 03:04pm", "70/01/01 12:01am"}, + {"layout=06/01/02 03:04pm", "70/01/01 12:01am"}, {"", 100.050005}, {"something-random", 100.050005}, {"rfc3339", "1970-01-01T00:01:40Z"}, From 5f2bb49e437d69e06f6ad74865a36ae417aa3922 Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Sat, 20 Jun 2020 21:19:53 +0900 Subject: [PATCH 05/10] fix timeEncoder test: use yaml.Unmarshal and json.Unmarshal --- go.mod | 1 + zapcore/encoder_test.go | 59 ++++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 118abda15..6ef4db70e 100644 --- a/go.mod +++ b/go.mod @@ -8,5 +8,6 @@ require ( go.uber.org/atomic v1.6.0 go.uber.org/multierr v1.5.0 golang.org/x/lint v0.0.0-20190930215403-16217165b5de + gopkg.in/yaml.v2 v2.2.2 honnef.co/go/tools v0.0.1-2019.2.3 ) diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index baa97500f..99383ce45 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -21,10 +21,13 @@ package zapcore_test import ( + "encoding/json" "strings" "testing" "time" + "gopkg.in/yaml.v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -523,30 +526,54 @@ func TestLevelEncoders(t *testing.T) { func TestTimeEncoders(t *testing.T) { moment := time.Unix(100, 50005000).UTC() tests := []struct { - name string + yamlDoc string + expected interface{} // output of serializing moment + }{ + {"timeEncoder: iso8601", "1970-01-01T00:01:40.050Z"}, + {"timeEncoder: ISO8601", "1970-01-01T00:01:40.050Z"}, + {"timeEncoder: millis", 100050.005}, + {"timeEncoder: nanos", int64(100050005000)}, + {"timeEncoder: layout=06/01/02 03:04pm", "70/01/01 12:01am"}, + {"timeEncoder: ''", 100.050005}, + {"timeEncoder: something-random", 100.050005}, + {"timeEncoder: rfc3339", "1970-01-01T00:01:40Z"}, + {"timeEncoder: RFC3339", "1970-01-01T00:01:40Z"}, + {"timeEncoder: rfc3339nano", "1970-01-01T00:01:40.050005Z"}, + {"timeEncoder: RFC3339Nano", "1970-01-01T00:01:40.050005Z"}, + } + + for _, tt := range tests { + cfg := EncoderConfig{} + require.NoError(t, yaml.Unmarshal([]byte(tt.yamlDoc), &cfg), "Unexpected error unmarshaling %q.", tt.yamlDoc) + require.NotNil(t, cfg.EncodeTime, "Unmashalled timeEncoder is nil for %q.", tt.yamlDoc) + assertAppended( + t, + tt.expected, + func(arr ArrayEncoder) { cfg.EncodeTime(moment, arr) }, + "Unexpected output serializing %v with %q.", moment, tt.yamlDoc, + ) + } +} + +func TestTimeEncodersParseFromJson(t *testing.T) { + moment := time.Unix(100, 50005000).UTC() + tests := []struct { + jsonDoc string expected interface{} // output of serializing moment }{ - {"iso8601", "1970-01-01T00:01:40.050Z"}, - {"ISO8601", "1970-01-01T00:01:40.050Z"}, - {"millis", 100050.005}, - {"nanos", int64(100050005000)}, - {"layout=06/01/02 03:04pm", "70/01/01 12:01am"}, - {"", 100.050005}, - {"something-random", 100.050005}, - {"rfc3339", "1970-01-01T00:01:40Z"}, - {"RFC3339", "1970-01-01T00:01:40Z"}, - {"rfc3339nano", "1970-01-01T00:01:40.050005Z"}, - {"RFC3339Nano", "1970-01-01T00:01:40.050005Z"}, + {`{"timeEncoder": "iso8601"}`, "1970-01-01T00:01:40.050Z"}, + {`{"timeEncoder": "layout=06/01/02 03:04pm"}`, "70/01/01 12:01am"}, } for _, tt := range tests { - var te TimeEncoder - require.NoError(t, te.UnmarshalText([]byte(tt.name)), "Unexpected error unmarshaling %q.", tt.name) + cfg := EncoderConfig{} + require.NoError(t, json.Unmarshal([]byte(tt.jsonDoc), &cfg), "Unexpected error unmarshaling %q.", tt.jsonDoc) + require.NotNil(t, cfg.EncodeTime, "Unmashalled timeEncoder is nil for %q.", tt.jsonDoc) assertAppended( t, tt.expected, - func(arr ArrayEncoder) { te(moment, arr) }, - "Unexpected output serializing %v with %q.", moment, tt.name, + func(arr ArrayEncoder) { cfg.EncodeTime(moment, arr) }, + "Unexpected output serializing %v with %q.", moment, tt.jsonDoc, ) } } From 0c345e23536349f06d0694b1aa961b83ae2e33ee Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Sat, 20 Jun 2020 21:29:46 +0900 Subject: [PATCH 06/10] change timeEncoder format for custom layout --- zapcore/encoder.go | 37 +++++++++++++++++++++++++++++++------ zapcore/encoder_test.go | 4 ++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index bcc858c3b..219ff56ff 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -21,7 +21,7 @@ package zapcore import ( - "strings" + "encoding/json" "time" "go.uber.org/zap/buffer" @@ -166,11 +166,9 @@ func TimeEncoderOfLayout(layout string) TimeEncoder { // "iso8601" and "ISO8601" are unmarshaled to ISO8601TimeEncoder. // "millis" is unmarshaled to EpochMillisTimeEncoder. // "nanos" is unmarshaled to EpochNanosEncoder. -// "layout=" is unmarshaled to TimeEncoder with given layout. // Anything else is unmarshaled to EpochTimeEncoder. func (e *TimeEncoder) UnmarshalText(text []byte) error { - vals := strings.SplitAfterN(string(text), "=", 2) - switch vals[0] { + switch string(text) { case "rfc3339nano", "RFC3339Nano": *e = RFC3339NanoTimeEncoder case "rfc3339", "RFC3339": @@ -181,14 +179,41 @@ func (e *TimeEncoder) UnmarshalText(text []byte) error { *e = EpochMillisTimeEncoder case "nanos": *e = EpochNanosTimeEncoder - case "layout=": - *e = TimeEncoderOfLayout(vals[1]) default: *e = EpochTimeEncoder } return nil } +// UnmarshalYAML unmarshals yaml to a TimeEncoder. +// If value is an object with a "layout" field, it will be unmarshaled to TimeEncoder with given layout. +// timeEncoder: +// layout: 06/01/02 03:04pm +// If value is string, it uses UnmarshalText. +// timeEncoder: iso8601 +func (e *TimeEncoder) UnmarshalYAML(unmarshal func(interface{}) error) error { + var o struct { + Layout string `json:"layout" yaml:"layout"` + } + if err := unmarshal(&o); err == nil { + *e = TimeEncoderOfLayout(o.Layout) + return nil + } + + var s string + if err := unmarshal(&s); err != nil { + return err + } + return e.UnmarshalText([]byte(s)) +} + +// UnmarshalJSON unmarshals yaml to a TimeEncoder as same way UnmarshalYAML does. +func (e *TimeEncoder) UnmarshalJSON(data []byte) error { + return e.UnmarshalYAML(func(v interface{}) error { + return json.Unmarshal(data, v) + }) +} + // A DurationEncoder serializes a time.Duration to a primitive type. type DurationEncoder func(time.Duration, PrimitiveArrayEncoder) diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 99383ce45..33f84f519 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -533,7 +533,7 @@ func TestTimeEncoders(t *testing.T) { {"timeEncoder: ISO8601", "1970-01-01T00:01:40.050Z"}, {"timeEncoder: millis", 100050.005}, {"timeEncoder: nanos", int64(100050005000)}, - {"timeEncoder: layout=06/01/02 03:04pm", "70/01/01 12:01am"}, + {"timeEncoder: {layout: 06/01/02 03:04pm}", "70/01/01 12:01am"}, {"timeEncoder: ''", 100.050005}, {"timeEncoder: something-random", 100.050005}, {"timeEncoder: rfc3339", "1970-01-01T00:01:40Z"}, @@ -562,7 +562,7 @@ func TestTimeEncodersParseFromJson(t *testing.T) { expected interface{} // output of serializing moment }{ {`{"timeEncoder": "iso8601"}`, "1970-01-01T00:01:40.050Z"}, - {`{"timeEncoder": "layout=06/01/02 03:04pm"}`, "70/01/01 12:01am"}, + {`{"timeEncoder": {"layout": "06/01/02 03:04pm"}}`, "70/01/01 12:01am"}, } for _, tt := range tests { From d907620e224c0b6c0661cfe445f978be8222320f Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Wed, 24 Jun 2020 00:38:41 +0900 Subject: [PATCH 07/10] add irregular tests for unmarshalling timeEncoder --- zapcore/encoder_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 33f84f519..a5e3acb16 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -555,6 +555,17 @@ func TestTimeEncoders(t *testing.T) { } } +func TestTimeEncodersWrongYAML(t *testing.T) { + tests := []string{ + "timeEncoder: [1, 2, 3]", // wrong type + "timeEncoder: {foo:bar", // broken yaml + } + for _, tt := range tests { + cfg := EncoderConfig{} + assert.Error(t, yaml.Unmarshal([]byte(tt), &cfg), "Expected unmarshaling %q to become error, but not.", tt) + } +} + func TestTimeEncodersParseFromJson(t *testing.T) { moment := time.Unix(100, 50005000).UTC() tests := []struct { From 16506e181c1f3976620ef9c58c5b14b8203ee927 Mon Sep 17 00:00:00 2001 From: Shinichi TAMURA Date: Wed, 24 Jun 2020 11:24:46 +0900 Subject: [PATCH 08/10] Apply suggestions from code review abbrev should be UPPERCASE Co-authored-by: Abhinav Gupta --- zapcore/encoder.go | 2 +- zapcore/encoder_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index 219ff56ff..a53ea0712 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -185,7 +185,7 @@ func (e *TimeEncoder) UnmarshalText(text []byte) error { return nil } -// UnmarshalYAML unmarshals yaml to a TimeEncoder. +// UnmarshalYAML unmarshals YAML to a TimeEncoder. // If value is an object with a "layout" field, it will be unmarshaled to TimeEncoder with given layout. // timeEncoder: // layout: 06/01/02 03:04pm diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index a5e3acb16..6c4dad6da 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -566,7 +566,7 @@ func TestTimeEncodersWrongYAML(t *testing.T) { } } -func TestTimeEncodersParseFromJson(t *testing.T) { +func TestTimeEncodersParseFromJSON(t *testing.T) { moment := time.Unix(100, 50005000).UTC() tests := []struct { jsonDoc string From 2b4b7f76d35c0c52f500995481d923e61452077d Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Wed, 24 Jun 2020 11:26:08 +0900 Subject: [PATCH 09/10] fix docs s/json/YAML --- zapcore/encoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zapcore/encoder.go b/zapcore/encoder.go index a53ea0712..db97aa332 100644 --- a/zapcore/encoder.go +++ b/zapcore/encoder.go @@ -207,7 +207,7 @@ func (e *TimeEncoder) UnmarshalYAML(unmarshal func(interface{}) error) error { return e.UnmarshalText([]byte(s)) } -// UnmarshalJSON unmarshals yaml to a TimeEncoder as same way UnmarshalYAML does. +// UnmarshalJSON unmarshals JSON to a TimeEncoder as same way UnmarshalYAML does. func (e *TimeEncoder) UnmarshalJSON(data []byte) error { return e.UnmarshalYAML(func(v interface{}) error { return json.Unmarshal(data, v) From c6de7e9c783b51707bc7962284be5f08d86883f6 Mon Sep 17 00:00:00 2001 From: "Shinichi TAMURA (@tmshn)" Date: Wed, 24 Jun 2020 11:26:36 +0900 Subject: [PATCH 10/10] fix import order --- zapcore/encoder_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zapcore/encoder_test.go b/zapcore/encoder_test.go index 6c4dad6da..206a7bd30 100644 --- a/zapcore/encoder_test.go +++ b/zapcore/encoder_test.go @@ -26,10 +26,9 @@ import ( "testing" "time" - "gopkg.in/yaml.v2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" . "go.uber.org/zap/zapcore" )