Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ package log
import (
"context"
"fmt"
"strconv"
"strings"

"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -120,8 +122,19 @@ const (
// - "error" ([ErrorLevel])
// - "fatal" ([FatalLevel])
// - "panic" ([PanicLevel])
//
// In addition, a numeric value can be provided using
// the level range defined by Go's slog library:
//
// - -8: trace
// - -4: debug
// - 0: info
// - 4: warn
// - 8: error
// - 10: fatal
// - 12: panic
func SetLevel(level string) error {
lvl, err := logrus.ParseLevel(level)
lvl, err := parseLevel(level)
if err != nil {
return err
}
Expand All @@ -130,6 +143,50 @@ func SetLevel(level string) error {
return nil
}

func parseLevel(level string) (Level, error) {
switch strings.ToLower(level) {
case "trace":
return TraceLevel, nil
case "debug":
return DebugLevel, nil
case "info":
return InfoLevel, nil
case "warn", "warning":
return WarnLevel, nil
case "error":
return ErrorLevel, nil
case "fatal":
return FatalLevel, nil
case "panic":
return PanicLevel, nil
}

// Default to parsing as numeric level
if v, err := strconv.Atoi(level); err == nil {
return numericLevel(v), nil
}
return InfoLevel, fmt.Errorf("unknown log level: %s", level)
}

// numericLevel returns the logrus level for the given integer value,
// choosing the nearest level without going above the given value.
func numericLevel(v int) Level {
if v <= -8 {
return TraceLevel
} else if v <= -4 {
return DebugLevel
} else if v <= 0 {
return InfoLevel
} else if v <= 4 {
return WarnLevel
} else if v <= 8 {
return ErrorLevel
} else if v <= 10 {
return FatalLevel
}
return PanicLevel
}

// GetLevel returns the current log level.
func GetLevel() Level {
return L.Logger.GetLevel()
Expand Down
64 changes: 64 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,70 @@ func TestLoggerContext(t *testing.T) {
}
}

func TestSetLevel(t *testing.T) {
for _, tc := range []struct {
input string
expected Level
wantErr bool
}{
// Named levels
{input: "trace", expected: TraceLevel},
{input: "debug", expected: DebugLevel},
{input: "info", expected: InfoLevel},
{input: "warn", expected: WarnLevel},
{input: "warning", expected: WarnLevel},
{input: "error", expected: ErrorLevel},
{input: "fatal", expected: FatalLevel},
{input: "panic", expected: PanicLevel},
{input: "INFO", expected: InfoLevel},
{input: "DEBUG", expected: DebugLevel},

// Exact numeric levels
{input: "-8", expected: TraceLevel},
{input: "-4", expected: DebugLevel},
{input: "0", expected: InfoLevel},
{input: "4", expected: WarnLevel},
{input: "8", expected: ErrorLevel},
{input: "10", expected: FatalLevel},
{input: "12", expected: PanicLevel},

// Nearest numeric levels (without going above)
{input: "-10", expected: TraceLevel},
{input: "-6", expected: DebugLevel},
{input: "-5", expected: DebugLevel},
{input: "-2", expected: InfoLevel},
{input: "1", expected: WarnLevel},
{input: "2", expected: WarnLevel},
{input: "3", expected: WarnLevel},
{input: "6", expected: ErrorLevel},
{input: "7", expected: ErrorLevel},
{input: "9", expected: FatalLevel},
{input: "11", expected: PanicLevel},
{input: "13", expected: PanicLevel},
{input: "100", expected: PanicLevel},

// Invalid
{input: "bogus", wantErr: true},
{input: "", wantErr: true},
} {
t.Run(tc.input, func(t *testing.T) {
err := SetLevel(tc.input)
if tc.wantErr {
if err == nil {
t.Fatal("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if actual := GetLevel(); actual != tc.expected {
t.Errorf("expected level %v, got %v", tc.expected, actual)
}
})
}
}

func TestCompat(t *testing.T) {
expected := Fields{
"hello1": "world1",
Expand Down
Loading