diff --git a/globals.go b/globals.go index 3e6fc9c..2024137 100644 --- a/globals.go +++ b/globals.go @@ -13,6 +13,11 @@ var ( // LevelFieldName is the field name used for the level field. 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 = "message" @@ -27,7 +32,7 @@ var ( // CallerMarshalFunc allows customization of global caller marshaling 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. diff --git a/log.go b/log.go index 8eb45a8..5508d5a 100644 --- a/log.go +++ b/log.go @@ -152,19 +152,19 @@ func (l Level) String() string { // returns an error if the input string does not match known values. func ParseLevel(levelStr string) (Level, error) { switch levelStr { - case DebugLevel.String(): + case LevelFieldMarshalFunc(DebugLevel): return DebugLevel, nil - case InfoLevel.String(): + case LevelFieldMarshalFunc(InfoLevel): return InfoLevel, nil - case WarnLevel.String(): + case LevelFieldMarshalFunc(WarnLevel): return WarnLevel, nil - case ErrorLevel.String(): + case LevelFieldMarshalFunc(ErrorLevel): return ErrorLevel, nil - case FatalLevel.String(): + case LevelFieldMarshalFunc(FatalLevel): return FatalLevel, nil - case PanicLevel.String(): + case LevelFieldMarshalFunc(PanicLevel): return PanicLevel, nil - case NoLevel.String(): + case LevelFieldMarshalFunc(NoLevel): return NoLevel, nil } 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.ch = l.hooks if level != NoLevel { - e.Str(LevelFieldName, level.String()) + e.Str(LevelFieldName, LevelFieldMarshalFunc(level)) } if l.context != nil && len(l.context) > 0 { e.buf = enc.AppendObjectData(e.buf, l.context) diff --git a/log_test.go b/log_test.go index a99224a..b796631 100644 --- a/log_test.go +++ b/log_test.go @@ -650,9 +650,9 @@ func TestCallerMarshalFunc(t *testing.T) { // test default behaviour this is really brittle due to the line numbers // actually mattering for validation _, 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") - 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) } out.Reset() @@ -663,19 +663,55 @@ func TestCallerMarshalFunc(t *testing.T) { CallerMarshalFunc = func(file string, line int) string { parts := strings.Split(file, "/") 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 { - return file+":"+strconv.Itoa(line) + return file + ":" + strconv.Itoa(line) } } _, file, line, _ = runtime.Caller(0) caller = CallerMarshalFunc(file, line+2) 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) } } +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 { error }