diff --git a/pkg/log/zap/flags.go b/pkg/log/zap/flags.go index 3339655075..7fa080b6b5 100644 --- a/pkg/log/zap/flags.go +++ b/pkg/log/zap/flags.go @@ -128,3 +128,41 @@ func (ev *stackTraceFlag) String() string { func (ev *stackTraceFlag) Type() string { return "level" } + +type timeEncodingFlag struct { + setFunc func(zapcore.TimeEncoder) + value string +} + +var _ flag.Value = &timeEncodingFlag{} + +func (ev *timeEncodingFlag) String() string { + return ev.value +} + +func (ev *timeEncodingFlag) Type() string { + return "time-encoder" +} + +func (ev *timeEncodingFlag) Set(flagValue string) error { + val := strings.ToLower(flagValue) + switch val { + case "rfc3339nano": + ev.setFunc(zapcore.RFC3339NanoTimeEncoder) + case "rfc3339": + ev.setFunc(zapcore.RFC3339TimeEncoder) + case "iso8601": + ev.setFunc(zapcore.ISO8601TimeEncoder) + case "millis": + ev.setFunc(zapcore.EpochMillisTimeEncoder) + case "nanos": + ev.setFunc(zapcore.EpochNanosTimeEncoder) + case "epoch": + ev.setFunc(zapcore.EpochTimeEncoder) + default: + return fmt.Errorf("invalid time-encoder value \"%s\"", flagValue) + } + + ev.value = flagValue + return nil +} diff --git a/pkg/log/zap/zap.go b/pkg/log/zap/zap.go index 22eb5d771a..d53a14156f 100644 --- a/pkg/log/zap/zap.go +++ b/pkg/log/zap/zap.go @@ -273,6 +273,15 @@ func (o *Options) BindFlags(fs *flag.FlagSet) { } fs.Var(&stackVal, "zap-stacktrace-level", "Zap Level at and above which stacktraces are captured (one of 'info', 'error', 'panic').") + + // Set the time encoding + var timeEncoderVal timeEncodingFlag + timeEncoderVal.setFunc = func(fromFlag zapcore.TimeEncoder) { + o.EncoderConfigOptions = append(o.EncoderConfigOptions, func(ec *zapcore.EncoderConfig) { + ec.EncodeTime = fromFlag + }) + } + fs.Var(&timeEncoderVal, "zap-time-encoding", "Zap time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano')") } // UseFlagOptions configures the logger to use the Options set by parsing zap option flags from the CLI. diff --git a/pkg/log/zap/zap_test.go b/pkg/log/zap/zap_test.go index 095fc54598..1647b9de42 100644 --- a/pkg/log/zap/zap_test.go +++ b/pkg/log/zap/zap_test.go @@ -472,6 +472,38 @@ var _ = Describe("Zap log level flag options setup", func() { }) }) + Context("with zap-time-encoding flag provided", func() { + + It("Should use ISO8601TimeEncoder, with iso8601 as time encoding specified", func() { + // zaps ISO8601TimeEncoder uses 2006-01-02T15:04:05.000Z0700 as pattern for iso8601 encoding + iso8601Pattern := `^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}(\+[0-9]{4}|Z)` + + args := []string{"--zap-time-encoding=iso8601"} + fromFlags.BindFlags(&fs) + err := fs.Parse(args) + Expect(err).ToNot(HaveOccurred()) + logOut := new(bytes.Buffer) + + logger := New(UseFlagOptions(&fromFlags), WriteTo(logOut)) + logger.Info("This is a test message") + + outRaw := logOut.Bytes() + + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + Expect(res["ts"]).Should(MatchRegexp(iso8601Pattern)) + }) + + It("Should return an error message, with unknown time-encoding", func() { + fs = *flag.NewFlagSet(os.Args[0], flag.ContinueOnError) + args := []string{"--zap-time-encoding=foobar"} + fromFlags.BindFlags(&fs) + err := fs.Parse(args) + Expect(err).To(HaveOccurred()) + }) + + }) + Context("with encoder options provided programmatically", func() { It("Should set Console Encoder, with given Nanos TimeEncoder option.", func() {