Skip to content

Commit

Permalink
feat(encoder): Add LevelFormatter to TextEncoder config
Browse files Browse the repository at this point in the history
  • Loading branch information
OscarClemente authored and damianopetrungaro committed Aug 22, 2022
1 parent 238aed8 commit f663020
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 59 deletions.
4 changes: 3 additions & 1 deletion datadog/datadog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 12 additions & 3 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -31,7 +35,7 @@ type TextConfig struct {
LevelKeyName string
MessageKeyName string
TimeLayout string
ColouredLevel bool
LevelFormatter LevelFormatter
}

// TextEncoder is an encoder for text
Expand All @@ -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)
Expand Down
79 changes: 79 additions & 0 deletions encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}
30 changes: 0 additions & 30 deletions level.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
25 changes: 0 additions & 25 deletions level_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}

0 comments on commit f663020

Please sign in to comment.