diff --git a/log/log.go b/log/log.go index ce82b1e..85d05f6 100644 --- a/log/log.go +++ b/log/log.go @@ -4,13 +4,22 @@ import ( "bytes" "fmt" "os" - "sync" "github.com/icexin/eggos/console" "github.com/icexin/eggos/drivers/uart" "github.com/icexin/eggos/kernel/sys" ) +type LogLevel int8 + +const ( + LoglvlDebug LogLevel = iota + LoglvlInfo + LoglvlWarn + LoglvlError + LoglvlNone +) + const ( loglvlEnv = "EGGOS_LOGLVL" loglvlEnvDebug = "debug" @@ -19,39 +28,43 @@ const ( loglvlEnvError = "error" loglvlEnvNone = "none" - loglvlDebug = iota - loglvlInfo - loglvlWarn - loglvlError - loglvlNone - - defaultLoglvl = loglvlError + defaultLoglvl = LoglvlError ) var ( - loglvl int - loglvlonce sync.Once + Level LogLevel + + ErrInvalidLogLevel = fmt.Errorf("invalid log level") ) -func setLoglvl() { +func init() { lvl := os.Getenv("EGGOS_LOGLVL") switch lvl { case loglvlEnvDebug: - loglvl = loglvlDebug + Level = LoglvlDebug case loglvlEnvInfo: - loglvl = loglvlInfo + Level = LoglvlInfo case loglvlEnvWarn: - loglvl = loglvlWarn + Level = LoglvlWarn case loglvlEnvError: - loglvl = loglvlError + Level = LoglvlError default: - loglvl = defaultLoglvl + Level = defaultLoglvl } } -func logf(lvl int, fmtstr string, args ...interface{}) { - loglvlonce.Do(setLoglvl) - if lvl < loglvl { +func SetLevel(l LogLevel) error { + if l < LoglvlDebug || l > LoglvlNone { + return ErrInvalidLogLevel + } + + Level = l + + return nil +} + +func logf(lvl LogLevel, fmtstr string, args ...interface{}) { + if lvl < Level { return } @@ -62,19 +75,19 @@ func logf(lvl int, fmtstr string, args ...interface{}) { } func Debugf(fmtstr string, args ...interface{}) { - logf(loglvlDebug, fmtstr, args...) + logf(LoglvlDebug, fmtstr, args...) } func Infof(fmtstr string, args ...interface{}) { - logf(loglvlInfo, fmtstr, args...) + logf(LoglvlInfo, fmtstr, args...) } func Warnf(fmtstr string, args ...interface{}) { - logf(loglvlWarn, fmtstr, args...) + logf(LoglvlWarn, fmtstr, args...) } func Errorf(fmtstr string, args ...interface{}) { - logf(loglvlError, fmtstr, args...) + logf(LoglvlError, fmtstr, args...) } //go:nosplit diff --git a/log/log_test.go b/log/log_test.go new file mode 100644 index 0000000..7e0a3de --- /dev/null +++ b/log/log_test.go @@ -0,0 +1,48 @@ +package log_test + +import ( + "testing" + + "github.com/icexin/eggos/log" +) + +func ExampleSetLogLevel() { + // Set the log level to Debug + log.Level = log.LoglvlDebug +} + +func TestLog_SetLevel(t *testing.T) { + for _, test := range []struct { + name string + l log.LogLevel + expectError bool + }{ + // These two cases require users to do something pretty explcitly + // wrong to hit, but they're worth catching + {"log level is too low", log.LogLevel(-1), true}, + {"log level is too high", log.LogLevel(6), true}, + + // Included log levels + {"log.LoglvlDebug is valid", log.LoglvlDebug, false}, + {"log.LoglvlInfo is valid", log.LoglvlInfo, false}, + {"log.LoglvlWarn is valid", log.LoglvlWarn, false}, + {"log.LoglvlError is valid", log.LoglvlError, false}, + {"log.LoglvlNone is valid", log.LoglvlNone, false}, + } { + t.Run(test.name, func(t *testing.T) { + err := log.SetLevel(test.l) + + if err == nil && test.expectError { + t.Error("expected error, received none") + } else if err != nil && !test.expectError { + t.Errorf("unexpected error: %#v", err) + } + + if !test.expectError { + if log.Level != test.l { + t.Errorf("log.Level should be %#v, received %#v", log.Level, test.l) + } + } + }) + } +}