Allow using custom level field format (#136)

This commit is contained in:
Soloman Weng 2019-03-02 10:08:23 +10:00 committed by Olivier Poitrey
parent 6d6350a511
commit 8e5449ab35
3 changed files with 55 additions and 14 deletions

View File

@ -13,6 +13,11 @@ var (
// LevelFieldName is the field name used for the level field. // LevelFieldName is the field name used for the level field.
LevelFieldName = "level" LevelFieldName = "level"
// LevelFieldMarshalFunc allows customization of global level field marshaling
LevelFieldMarshalFunc = func(l Level) string {
return l.String()
}
// MessageFieldName is the field name used for the message field. // MessageFieldName is the field name used for the message field.
MessageFieldName = "message" MessageFieldName = "message"
@ -27,7 +32,7 @@ var (
// CallerMarshalFunc allows customization of global caller marshaling // CallerMarshalFunc allows customization of global caller marshaling
CallerMarshalFunc = func(file string, line int) string { CallerMarshalFunc = func(file string, line int) string {
return file+":"+strconv.Itoa(line) return file + ":" + strconv.Itoa(line)
} }
// ErrorStackFieldName is the field name used for error stacks. // ErrorStackFieldName is the field name used for error stacks.

16
log.go
View File

@ -152,19 +152,19 @@ func (l Level) String() string {
// returns an error if the input string does not match known values. // returns an error if the input string does not match known values.
func ParseLevel(levelStr string) (Level, error) { func ParseLevel(levelStr string) (Level, error) {
switch levelStr { switch levelStr {
case DebugLevel.String(): case LevelFieldMarshalFunc(DebugLevel):
return DebugLevel, nil return DebugLevel, nil
case InfoLevel.String(): case LevelFieldMarshalFunc(InfoLevel):
return InfoLevel, nil return InfoLevel, nil
case WarnLevel.String(): case LevelFieldMarshalFunc(WarnLevel):
return WarnLevel, nil return WarnLevel, nil
case ErrorLevel.String(): case LevelFieldMarshalFunc(ErrorLevel):
return ErrorLevel, nil return ErrorLevel, nil
case FatalLevel.String(): case LevelFieldMarshalFunc(FatalLevel):
return FatalLevel, nil return FatalLevel, nil
case PanicLevel.String(): case LevelFieldMarshalFunc(PanicLevel):
return PanicLevel, nil return PanicLevel, nil
case NoLevel.String(): case LevelFieldMarshalFunc(NoLevel):
return NoLevel, nil return NoLevel, nil
} }
return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
@ -380,7 +380,7 @@ func (l *Logger) newEvent(level Level, done func(string)) *Event {
e.done = done e.done = done
e.ch = l.hooks e.ch = l.hooks
if level != NoLevel { if level != NoLevel {
e.Str(LevelFieldName, level.String()) e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
} }
if l.context != nil && len(l.context) > 0 { if l.context != nil && len(l.context) > 0 {
e.buf = enc.AppendObjectData(e.buf, l.context) e.buf = enc.AppendObjectData(e.buf, l.context)

View File

@ -650,9 +650,9 @@ func TestCallerMarshalFunc(t *testing.T) {
// test default behaviour this is really brittle due to the line numbers // test default behaviour this is really brittle due to the line numbers
// actually mattering for validation // actually mattering for validation
_, file, line, _ := runtime.Caller(0) _, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line + 2) caller := fmt.Sprintf("%s:%d", file, line+2)
log.Log().Caller().Msg("msg") log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"` + caller + `","message":"msg"}`+"\n"; got != want { if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
} }
out.Reset() out.Reset()
@ -663,19 +663,55 @@ func TestCallerMarshalFunc(t *testing.T) {
CallerMarshalFunc = func(file string, line int) string { CallerMarshalFunc = func(file string, line int) string {
parts := strings.Split(file, "/") parts := strings.Split(file, "/")
if len(parts) > 1 { if len(parts) > 1 {
return strings.Join(parts[len(parts)-2:], "/")+":"+strconv.Itoa(line) return strings.Join(parts[len(parts)-2:], "/") + ":" + strconv.Itoa(line)
} else { } else {
return file+":"+strconv.Itoa(line) return file + ":" + strconv.Itoa(line)
} }
} }
_, file, line, _ = runtime.Caller(0) _, file, line, _ = runtime.Caller(0)
caller = CallerMarshalFunc(file, line+2) caller = CallerMarshalFunc(file, line+2)
log.Log().Caller().Msg("msg") log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"` + caller + `","message":"msg"}`+"\n"; got != want { if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
} }
} }
func TestLevelFieldMarshalFunc(t *testing.T) {
origLevelFieldMarshalFunc := LevelFieldMarshalFunc
LevelFieldMarshalFunc = func(l Level) string {
return strings.ToUpper(l.String())
}
defer func() {
LevelFieldMarshalFunc = origLevelFieldMarshalFunc
}()
out := &bytes.Buffer{}
log := New(out)
log.Debug().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"DEBUG","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Info().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"INFO","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Warn().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"WARN","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Error().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"ERROR","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
}
type errWriter struct { type errWriter struct {
error error
} }