From f6630206224bcd205d281185bb217be67f1eba3b Mon Sep 17 00:00:00 2001 From: OscarClemente Date: Tue, 16 Aug 2022 20:14:29 +0200 Subject: [PATCH] feat(encoder): Add LevelFormatter to TextEncoder config --- datadog/datadog_test.go | 4 ++- encoder.go | 15 ++++++-- encoder_test.go | 79 +++++++++++++++++++++++++++++++++++++++++ level.go | 30 ---------------- level_test.go | 25 ------------- 5 files changed, 94 insertions(+), 59 deletions(-) diff --git a/datadog/datadog_test.go b/datadog/datadog_test.go index 238253b..785d420 100644 --- a/datadog/datadog_test.go +++ b/datadog/datadog_test.go @@ -73,7 +73,9 @@ func TestDefaultTextConfig(t *testing.T) { func TestNewTextEncoder(t *testing.T) { cfg := DefaultTextConfig() enc := NewTextEncoder() - if enc.Config != cfg { + if enc.Config.MessageKeyName != cfg.MessageKeyName && + enc.Config.LevelKeyName != cfg.LevelKeyName && + enc.Config.TimeLayout != cfg.TimeLayout { t.Error("could not match config") t.Errorf("got: %v", enc.Config) t.Errorf("want: %v", cfg) diff --git a/encoder.go b/encoder.go index 9588cd9..11c418a 100644 --- a/encoder.go +++ b/encoder.go @@ -17,10 +17,14 @@ var ( LevelKeyName: "level", MessageKeyName: "message", TimeLayout: time.RFC3339Nano, - ColouredLevel: false, + LevelFormatter: func(level Level) string { + return level.String() + }, } ) +type LevelFormatter func(Level) string + // Encoder transforms an entry into io.WriterTo which holds the encoded content type Encoder interface { Encode(Entry) (io.WriterTo, error) @@ -31,7 +35,7 @@ type TextConfig struct { LevelKeyName string MessageKeyName string TimeLayout string - ColouredLevel bool + LevelFormatter LevelFormatter } // TextEncoder is an encoder for text @@ -52,7 +56,12 @@ func NewTextEncoder(cfg TextConfig) TextEncoder { // Encode encodes an entry into a text content holds into an io.WriterTo func (t TextEncoder) Encode(e Entry) (io.WriterTo, error) { w := &bytes.Buffer{} - t.addElemQuoted(w, t.Config.LevelKeyName, e.Level().Formatted(t.Config.ColouredLevel)) + switch t.Config.LevelFormatter { + case nil: + t.addElemQuoted(w, t.Config.LevelKeyName, e.Level().String()) + default: + t.addElemQuoted(w, t.Config.LevelKeyName, t.Config.LevelFormatter(e.Level())) + } w.WriteString(` `) t.addElemQuoted(w, t.Config.MessageKeyName, e.Message()) t.encodeFields(e.Fields(), w) diff --git a/encoder_test.go b/encoder_test.go index c774bca..6c61ac4 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -228,3 +228,82 @@ func TestTextEncoder_Encode(t *testing.T) { }) } } + +func TestTextEncoder_EncodeWithCustomLevelFormatter(t *testing.T) { + cfg := DefaultTextConfig() + cfg.LevelFormatter = func(l Level) string { + var colour string + + switch l { + case DEBUG: + colour = COLOUR_GREEN + case INFO: + colour = COLOUR_BLUE + case WARN: + colour = COLOUR_YELLOW + case ERROR: + colour = COLOUR_RED + case FATAL: + colour = COLOUR_REDBG + default: + return l.String() + } + + return colour + l.String() + COLOUR_RESET + } + + unknownLevel, _ := ParseLevel("unknown") + + tests := map[string]struct { + entry Entry + wantLog string + }{ + "debug entry": { + entry: NewStdEntry(context.Background(), DEBUG, "message", nil), + wantLog: fmt.Sprintf(`level="%sDEBUG%s" message="message"%s`, COLOUR_GREEN, COLOUR_RESET, "\n"), + }, + "info entry": { + entry: NewStdEntry(context.Background(), INFO, "message", nil), + wantLog: fmt.Sprintf(`level="%sINFO%s" message="message"%s`, COLOUR_BLUE, COLOUR_RESET, "\n"), + }, + "warn entry": { + entry: NewStdEntry(context.Background(), WARN, "message", nil), + wantLog: fmt.Sprintf(`level="%sWARN%s" message="message"%s`, COLOUR_YELLOW, COLOUR_RESET, "\n"), + }, + "error entry": { + entry: NewStdEntry(context.Background(), ERROR, "message", nil), + wantLog: fmt.Sprintf(`level="%sERROR%s" message="message"%s`, COLOUR_RED, COLOUR_RESET, "\n"), + }, + "fatal entry": { + entry: NewStdEntry(context.Background(), FATAL, "message", nil), + wantLog: fmt.Sprintf(`level="%sFATAL%s" message="message"%s`, COLOUR_REDBG, COLOUR_RESET, "\n"), + }, + "default entry": { + entry: NewStdEntry(context.Background(), unknownLevel, "message", nil), + wantLog: fmt.Sprintf(`level="" message="message"%s`, "\n"), + }, + } + + for name, test := range tests { + test := test + t.Run(name, func(t *testing.T) { + t.Parallel() + enc := NewTextEncoder(cfg) + w, err := enc.Encode(test.entry) + if err != nil { + t.Errorf("could not encode: %s", err) + } + + buf := &bytes.Buffer{} + if _, err := w.WriteTo(buf); err != nil { + t.Errorf("could not write: %s", err) + } + + if got := buf.String(); got != test.wantLog { + t.Error("could not match log") + t.Errorf("want: %s", test.wantLog) + t.Errorf("got: %s", got) + } + }) + } +} diff --git a/level.go b/level.go index 4dcc3ee..cb522e2 100644 --- a/level.go +++ b/level.go @@ -48,14 +48,6 @@ func ParseLevel(s string) (Level, error) { return 0, ErrLevelNotParsed } -func (l Level) Formatted(withColour bool) string { - if withColour { - return l.ColouredString() - } - - return l.String() -} - // String returns a string format of a log Level func (l Level) String() string { switch l { @@ -73,25 +65,3 @@ func (l Level) String() string { return "" } } - -// ColouredString returns a coloured string format of a log level -func (l Level) ColouredString() string { - colour := COLOUR_WHITE - - switch l { - case DEBUG: - colour = COLOUR_GREEN - case INFO: - colour = COLOUR_BLUE - case WARN: - colour = COLOUR_YELLOW - case ERROR: - colour = COLOUR_RED - case FATAL: - colour = COLOUR_REDBG - default: - return l.String() - } - - return colour + l.String() + COLOUR_RESET -} diff --git a/level_test.go b/level_test.go index 079af8a..ba70fad 100644 --- a/level_test.go +++ b/level_test.go @@ -66,28 +66,3 @@ func TestLevel_String(t *testing.T) { }) } } - -func TestLevel_ColouredString(t *testing.T) { - tests := map[string]struct { - given Level - want string - }{ - "a DEBUG level must return a coloured DEBUG": {given: DEBUG, want: "\033[32mDEBUG\033[0m"}, - "a INFO level must return a coloured INFO": {given: INFO, want: "\033[34mINFO\033[0m"}, - "a WARN level must return a coloured WARN": {given: WARN, want: "\033[33mWARN\033[0m"}, - "a ERROR level must return a coloured ERROR": {given: ERROR, want: "\033[31mERROR\033[0m"}, - "a FATAL level must return a coloured FATAL": {given: FATAL, want: "\033[41mFATAL\033[0m"}, - "a UNKNOWN level must return an empty string": {given: 0, want: ""}, - } - - for name, test := range tests { - test := test - t.Run(name, func(t *testing.T) { - if got := test.given.ColouredString(); got != test.want { - t.Error("could not match coloured string level") - t.Errorf("got: %s", got) - t.Errorf("want: %s", test.want) - } - }) - } -}