From 2173899f8f5b34385d0713b79ad2c4ff2071a850 Mon Sep 17 00:00:00 2001 From: Ryan Canty Date: Mon, 15 Aug 2016 11:04:25 -0700 Subject: [PATCH 1/4] Added customizable keys to JSON formatter --- json_formatter.go | 24 +++++++++++++++++++++--- json_formatter_test.go | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/json_formatter.go b/json_formatter.go index 2ad6dc5..7364fe8 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -8,6 +8,9 @@ import ( type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string + MessageKey string + LevelKey string + TimeKey string } func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { @@ -29,9 +32,24 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat = DefaultTimestampFormat } - data["time"] = entry.Time.Format(timestampFormat) - data["msg"] = entry.Message - data["level"] = entry.Level.String() + timeKey := f.TimeKey + if timeKey == "" { + timeKey = "time" + } + + messageKey := f.MessageKey + if messageKey == "" { + messageKey = "msg" + } + + levelKey := f.LevelKey + if levelKey == "" { + levelKey = "level" + } + + data[timeKey] = entry.Time.Format(timestampFormat) + data[messageKey] = entry.Message + data[levelKey] = entry.Level.String() serialized, err := json.Marshal(data) if err != nil { diff --git a/json_formatter_test.go b/json_formatter_test.go index 1d70873..0fa3466 100644 --- a/json_formatter_test.go +++ b/json_formatter_test.go @@ -3,7 +3,7 @@ package logrus import ( "encoding/json" "errors" - + "strings" "testing" ) @@ -118,3 +118,42 @@ func TestJSONEntryEndsWithNewline(t *testing.T) { t.Fatal("Expected JSON log entry to end with a newline") } } + +func TestJSONMessageKey(t *testing.T) { + formatter := &JSONFormatter{MessageKey: "message"} + + b, err := formatter.Format(&Entry{Message: "oh hai"}) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) { + t.Fatal("Expected JSON to format message key") + } +} + +func TestJSONLevelKey(t *testing.T) { + formatter := &JSONFormatter{LevelKey: "somelevel"} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "somelevel") { + t.Fatal("Expected JSON to format level key") + } +} + +func TestJSONTimeKey(t *testing.T) { + formatter := &JSONFormatter{TimeKey: "timeywimey"} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "timeywimey") { + t.Fatal("Expected JSON to format time key") + } +} From b2c6f8aa8b5298ac71ce8e3826c8cc417e6c7336 Mon Sep 17 00:00:00 2001 From: Ryan Canty Date: Thu, 17 Nov 2016 11:28:41 -0800 Subject: [PATCH 2/4] Added resolve method to clean up Format --- json_formatter.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/json_formatter.go b/json_formatter.go index 7364fe8..0c74e5a 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -5,6 +5,14 @@ import ( "fmt" ) +type fieldKey string + +const ( + DefaultKeyMsg = "msg" + DefaultKeyLevel = "level" + DefaultKeyTime = "time" +) + type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string @@ -32,24 +40,9 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat = DefaultTimestampFormat } - timeKey := f.TimeKey - if timeKey == "" { - timeKey = "time" - } - - messageKey := f.MessageKey - if messageKey == "" { - messageKey = "msg" - } - - levelKey := f.LevelKey - if levelKey == "" { - levelKey = "level" - } - - data[timeKey] = entry.Time.Format(timestampFormat) - data[messageKey] = entry.Message - data[levelKey] = entry.Level.String() + data[f.resolveKey(f.TimeKey, DefaultKeyTime)] = entry.Time.Format(timestampFormat) + data[f.resolveKey(f.MessageKey, DefaultKeyMsg)] = entry.Message + data[f.resolveKey(f.LevelKey, DefaultKeyLevel)] = entry.Level.String() serialized, err := json.Marshal(data) if err != nil { @@ -57,3 +50,10 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { } return append(serialized, '\n'), nil } + +func (f *JSONFormatter) resolveKey(key, defaultKey string) string { + if len(key) > 0 { + return key + } + return defaultKey +} From d5ca23f998921ce222ad9227e09a254e68fda4b8 Mon Sep 17 00:00:00 2001 From: Ryan Canty Date: Thu, 17 Nov 2016 15:16:46 -0800 Subject: [PATCH 3/4] Added FieldMap to reduce potential struct bloat --- json_formatter.go | 33 ++++++++++++++++----------------- json_formatter_test.go | 18 +++++++++++++++--- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/json_formatter.go b/json_formatter.go index 0c74e5a..1e3e2bc 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -4,21 +4,27 @@ import ( "encoding/json" "fmt" ) - type fieldKey string +type FieldMap map[fieldKey]string const ( - DefaultKeyMsg = "msg" - DefaultKeyLevel = "level" - DefaultKeyTime = "time" + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" ) +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string - MessageKey string - LevelKey string - TimeKey string + FieldMap FieldMap } func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { @@ -40,9 +46,9 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { timestampFormat = DefaultTimestampFormat } - data[f.resolveKey(f.TimeKey, DefaultKeyTime)] = entry.Time.Format(timestampFormat) - data[f.resolveKey(f.MessageKey, DefaultKeyMsg)] = entry.Message - data[f.resolveKey(f.LevelKey, DefaultKeyLevel)] = entry.Level.String() + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() serialized, err := json.Marshal(data) if err != nil { @@ -50,10 +56,3 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { } return append(serialized, '\n'), nil } - -func (f *JSONFormatter) resolveKey(key, defaultKey string) string { - if len(key) > 0 { - return key - } - return defaultKey -} diff --git a/json_formatter_test.go b/json_formatter_test.go index 0fa3466..5baa93e 100644 --- a/json_formatter_test.go +++ b/json_formatter_test.go @@ -120,7 +120,11 @@ func TestJSONEntryEndsWithNewline(t *testing.T) { } func TestJSONMessageKey(t *testing.T) { - formatter := &JSONFormatter{MessageKey: "message"} + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyMsg: "message", + }, + } b, err := formatter.Format(&Entry{Message: "oh hai"}) if err != nil { @@ -133,7 +137,11 @@ func TestJSONMessageKey(t *testing.T) { } func TestJSONLevelKey(t *testing.T) { - formatter := &JSONFormatter{LevelKey: "somelevel"} + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyLevel: "somelevel", + }, + } b, err := formatter.Format(WithField("level", "something")) if err != nil { @@ -146,7 +154,11 @@ func TestJSONLevelKey(t *testing.T) { } func TestJSONTimeKey(t *testing.T) { - formatter := &JSONFormatter{TimeKey: "timeywimey"} + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "timeywimey", + }, + } b, err := formatter.Format(WithField("level", "something")) if err != nil { From fcf4b8f2294f4097a4cc70639c0f5eb067e1b49c Mon Sep 17 00:00:00 2001 From: Ryan Canty Date: Fri, 18 Nov 2016 11:02:11 -0800 Subject: [PATCH 4/4] Added comment documentation for FieldMap --- json_formatter.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/json_formatter.go b/json_formatter.go index 1e3e2bc..f3729bf 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" ) + type fieldKey string type FieldMap map[fieldKey]string @@ -24,7 +25,17 @@ func (f FieldMap) resolve(key fieldKey) string { type JSONFormatter struct { // TimestampFormat sets the format used for marshaling timestamps. TimestampFormat string - FieldMap FieldMap + + // FieldMap allows users to customize the names of keys for various fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyLevel: "@message", + // }, + // } + FieldMap FieldMap } func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {