Skip to content

Commit

Permalink
Add zap-time-encoding flag
Browse files Browse the repository at this point in the history
    Adds the --zap-time-encoding flag to specify the output format of the log
    timestamp. Allows:
    epoch (floating-point number of seconds since the Unix epoch),
    nanos (integer of nanoseconds since the Unix epoch),
    millis (floating-point number of milliseconds since the Unix epoch),
    iso8601 (ISO8601-formatted string with millisecond precision),
    rfc3339 (RFC3339-formatted string) and
    rfc3339nano (RFC3339-formatted string with nanosecond precision).

Signed-off-by: Christoph Stäbler <cstabler@redhat.com>
  • Loading branch information
creydr committed Oct 8, 2021
1 parent e1880f5 commit 16b8425
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
38 changes: 38 additions & 0 deletions pkg/log/zap/flags.go
Expand Up @@ -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
}
9 changes: 9 additions & 0 deletions pkg/log/zap/zap.go
Expand Up @@ -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.
Expand Down
32 changes: 32 additions & 0 deletions pkg/log/zap/zap_test.go
Expand Up @@ -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}$`

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() {
Expand Down

0 comments on commit 16b8425

Please sign in to comment.