From b816156e7778c7eaa507bb514bed5de46ec3e33e Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Fri, 16 Oct 2020 09:53:22 +0300 Subject: [PATCH] accesslog: new HumanTime option as requested at #1661 --- middleware/accesslog/json.go | 42 +++++++++++++++++++++++++++++++ middleware/accesslog/json_easy.go | 14 ++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/middleware/accesslog/json.go b/middleware/accesslog/json.go index d978fdbd..1120b50c 100644 --- a/middleware/accesslog/json.go +++ b/middleware/accesslog/json.go @@ -1,7 +1,9 @@ package accesslog import ( + "bytes" "io" + "strconv" "strings" jsoniter "github.com/json-iterator/go" @@ -13,6 +15,7 @@ type JSON struct { // Note that, if set to > 0 then jsoniter is used instead of easyjson. Indent string EscapeHTML bool + HumanTime bool jsoniter jsoniter.API ac *AccessLog @@ -23,6 +26,8 @@ type JSON struct { func (f *JSON) SetOutput(dest io.Writer) { f.ac, _ = dest.(*AccessLog) if indentStep := strings.Count(f.Indent, " "); indentStep > 0 { + // Note that: indent setting should always be spaces + // as the jsoniter does not support other chars. f.jsoniter = jsoniter.Config{ TagKey: "json", IndentionStep: indentStep, @@ -32,15 +37,52 @@ func (f *JSON) SetOutput(dest io.Writer) { } } +var ( + timestampKeyB = []byte(`"timestamp":`) + timestampKeyIndentB = append(timestampKeyB, ' ') + timestampKeyVB = append(timestampKeyB, '0') + timestampIndentKeyVB = append(timestampKeyIndentB, '0') +) + // Format prints the logs in JSON format. // Writes to the destination directly, // locks on each Format call. func (f *JSON) Format(log *Log) (bool, error) { if f.jsoniter != nil { + if f.HumanTime { + // 1. Don't write the unix timestamp, + // key will be visible though as we don't omit the field. + log.Timestamp = 0 + } + b, err := f.jsoniter.Marshal(log) if err != nil { return true, err } + + if f.HumanTime { + // 2. Get the time text based on the configuration. + t := log.Now.Format(log.TimeFormat) + + // 3. Find the "timestamp:$indent" + // and set it to the text one. + var ( + oldT []byte + tsKey []byte + ) + + if f.Indent != "" { + oldT = timestampIndentKeyVB + tsKey = timestampKeyIndentB + } else { + oldT = timestampKeyVB + tsKey = timestampKeyB + } + + newT := append(tsKey, strconv.Quote(t)...) + b = bytes.Replace(b, oldT, newT, 1) + } + f.ac.Write(append(b, newLine)) return true, nil } diff --git a/middleware/accesslog/json_easy.go b/middleware/accesslog/json_easy.go index 468db4ad..2613233b 100644 --- a/middleware/accesslog/json_easy.go +++ b/middleware/accesslog/json_easy.go @@ -25,7 +25,13 @@ func (f *JSON) writeEasyJSON(in *Log) error { } else { out.RawString(prefix) } - out.Int64(int64(in.Timestamp)) + + if f.HumanTime { + t := in.Now.Format(in.TimeFormat) + out.String(t) + } else { + out.Int64(in.Timestamp) + } } { const prefix string = ",\"latency\":" @@ -40,17 +46,17 @@ func (f *JSON) writeEasyJSON(in *Log) error { { const prefix string = ",\"method\":" out.RawString(prefix) - out.String(string(in.Method)) + out.String(in.Method) } { const prefix string = ",\"path\":" out.RawString(prefix) - out.String(string(in.Path)) + out.String(in.Path) } if in.IP != "" { const prefix string = ",\"ip\":" out.RawString(prefix) - out.String(string(in.IP)) + out.String(in.IP) } if len(in.Query) != 0 { const prefix string = ",\"query\":"