From cdd74175d0c2b76240318987e212c69c55681d88 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Fri, 27 Aug 2021 13:34:08 -0700 Subject: [PATCH] Allow arbitrary negative levels (#350) This allows logr to use high V() levels. --- log.go | 14 +++++++++++--- log_test.go | 14 +++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/log.go b/log.go index 4cb7f29d..6227386d 100644 --- a/log.go +++ b/log.go @@ -129,6 +129,7 @@ const ( // TraceLevel defines trace log level. TraceLevel Level = -1 + // Values less than TraceLevel are handled as numbers. ) func (l Level) String() string { @@ -152,7 +153,7 @@ func (l Level) String() string { case NoLevel: return "" } - return "" + return strconv.Itoa(int(l)) } // ParseLevel converts a level string into a zerolog Level value. @@ -178,7 +179,14 @@ func ParseLevel(levelStr string) (Level, error) { case LevelFieldMarshalFunc(NoLevel): return NoLevel, nil } - return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) + i, err := strconv.Atoi(levelStr) + if err != nil { + return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) + } + if i > 127 || i < -128 { + return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i) + } + return Level(i), nil } // A Logger represents an active logging object that generates lines @@ -377,7 +385,7 @@ func (l *Logger) WithLevel(level Level) *Event { case Disabled: return nil default: - panic("zerolog: WithLevel(): invalid level: " + strconv.Itoa(int(level))) + return l.newEvent(level, nil) } } diff --git a/log_test.go b/log_test.go index 2d3d8fc6..e22e9269 100644 --- a/log_test.go +++ b/log_test.go @@ -549,7 +549,11 @@ func TestLevelWriter(t *testing.T) { p string }{}, } - log := New(lw) + + // Allow extra-verbose logs. + SetGlobalLevel(TraceLevel - 1) + log := New(lw).Level(TraceLevel - 1) + log.Trace().Msg("0") log.Debug().Msg("1") log.Info().Msg("2") @@ -562,6 +566,9 @@ func TestLevelWriter(t *testing.T) { log.WithLevel(WarnLevel).Msg("8") log.WithLevel(ErrorLevel).Msg("9") log.WithLevel(NoLevel).Msg("nolevel-2") + log.WithLevel(-1).Msg("-1") // Same as TraceLevel + log.WithLevel(-2).Msg("-2") // Will log + log.WithLevel(-3).Msg("-3") // Will not log want := []struct { l Level @@ -579,6 +586,8 @@ func TestLevelWriter(t *testing.T) { {WarnLevel, `{"level":"warn","message":"8"}` + "\n"}, {ErrorLevel, `{"level":"error","message":"9"}` + "\n"}, {NoLevel, `{"message":"nolevel-2"}` + "\n"}, + {Level(-1), `{"level":"trace","message":"-1"}` + "\n"}, + {Level(-2), `{"level":"-2","message":"-2"}` + "\n"}, } if got := lw.ops; !reflect.DeepEqual(got, want) { t.Errorf("invalid ops:\ngot:\n%v\nwant:\n%v", got, want) @@ -853,6 +862,9 @@ func TestParseLevel(t *testing.T) { {"panic", args{"panic"}, PanicLevel, false}, {"disabled", args{"disabled"}, Disabled, false}, {"nolevel", args{""}, NoLevel, false}, + {"-1", args{"-1"}, TraceLevel, false}, + {"-2", args{"-2"}, Level(-2), false}, + {"-3", args{"-3"}, Level(-3), false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {