From 5526934baaf18707addc79bf9ff3bd7c05004950 Mon Sep 17 00:00:00 2001 From: Hiroaki Nakamura Date: Sun, 17 Jul 2016 03:23:24 +0900 Subject: [PATCH 1/2] Add feature for cheking a log level is enabled --- log/levels/enabled/enabled.go | 89 ++++++++++++++++++++++++++++++ log/levels/enabled/enabled_test.go | 60 ++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 log/levels/enabled/enabled.go create mode 100644 log/levels/enabled/enabled_test.go diff --git a/log/levels/enabled/enabled.go b/log/levels/enabled/enabled.go new file mode 100644 index 000000000..aea4e008d --- /dev/null +++ b/log/levels/enabled/enabled.go @@ -0,0 +1,89 @@ +package enabled + +import "github.com/go-kit/kit/log/levels" + +// LevelEnabledLogger provides a wrapper around a logger with a feature +// for checking a level is enabled. It has five +// levels: debug, info, warning (warn), error, and critical (crit). +// +// It is users' responsibility not to call the Log method of a logger. +type LevelEnabledLogger struct { + levels.Levels + debugEnabled bool + infoEnabled bool + warnEnabled bool + errorEnabled bool + critEnabled bool +} + +// New creates a new level enabled logger, wrapping the passed logger. +func New(logger levels.Levels, option Option) LevelEnabledLogger { + l := LevelEnabledLogger{ + Levels: logger, + } + option(&l) + return l +} + +// DebugEnabled returns the debug level is enabled +func (l LevelEnabledLogger) DebugEnabled() bool { return l.debugEnabled } + +// InfoEnabled returns the info level is enabled +func (l LevelEnabledLogger) InfoEnabled() bool { return l.infoEnabled } + +// WarnEnabled returns the warn level is enabled +func (l LevelEnabledLogger) WarnEnabled() bool { return l.warnEnabled } + +// ErrorEnabled returns the error level is enabled +func (l LevelEnabledLogger) ErrorEnabled() bool { return l.errorEnabled } + +// CritEnabled returns the crit level is enabled +func (l LevelEnabledLogger) CritEnabled() bool { return l.critEnabled } + +// Option sets a parameter for level enabled loggers. +type Option func(*LevelEnabledLogger) + +// Debug enables all levels for the level enabled logger. +func Debug() Option { + return func(l *LevelEnabledLogger) { + l.debugEnabled = true + l.infoEnabled = true + l.warnEnabled = true + l.errorEnabled = true + l.critEnabled = true + } +} + +// Info enables info and above levels for the level enabled logger. +func Info() Option { + return func(l *LevelEnabledLogger) { + l.infoEnabled = true + l.warnEnabled = true + l.errorEnabled = true + l.critEnabled = true + } +} + +// Warn enables warn and above levels for the level enabled logger. +func Warn() Option { + return func(l *LevelEnabledLogger) { + l.warnEnabled = true + l.errorEnabled = true + l.critEnabled = true + } +} + +// Error enables error and above levels for the level enabled logger. +func Error() Option { + return func(l *LevelEnabledLogger) { + l.errorEnabled = true + l.critEnabled = true + } +} + +// Crit enables crit level for the level enabled logger. +func Crit() Option { + return func(l *LevelEnabledLogger) { + l.critEnabled = true + } +} diff --git a/log/levels/enabled/enabled_test.go b/log/levels/enabled/enabled_test.go new file mode 100644 index 000000000..4fbca22b5 --- /dev/null +++ b/log/levels/enabled/enabled_test.go @@ -0,0 +1,60 @@ +package enabled_test + +import ( + "bytes" + "os" + "testing" + + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/levels" + "github.com/go-kit/kit/log/levels/enabled" +) + +func TestInfoLevel(t *testing.T) { + buf := bytes.Buffer{} + logger := enabled.New(levels.New(log.NewLogfmtLogger(&buf)), enabled.Info()) + + if logger.DebugEnabled() { + logger.Debug().Log("msg", "résumé") // of course you'd want to do this + } + if want, have := "", buf.String(); want != have { + t.Errorf("want %#v, have %#v", want, have) + } + + buf.Reset() + if logger.InfoEnabled() { + logger.Info().Log("msg", "Åhus") + } + if want, have := "level=info msg=Åhus\n", buf.String(); want != have { + t.Errorf("want %#v, have %#v", want, have) + } + + buf.Reset() + if logger.ErrorEnabled() { + logger.Error().Log("msg", "© violation") + } + if want, have := "level=error msg=\"© violation\"\n", buf.String(); want != have { + t.Errorf("want %#v, have %#v", want, have) + } + + buf.Reset() + if logger.CritEnabled() { + logger.Crit().Log("msg", " ") + } + if want, have := "level=crit msg=\"\\t\"\n", buf.String(); want != have { + t.Errorf("want %#v, have %#v", want, have) + } +} + +func ExampleEnabled() { + logger := enabled.New(levels.New(log.NewLogfmtLogger(os.Stdout)), enabled.Warn()) + if logger.DebugEnabled() { + logger.Debug().Log("msg", "hello") + } + if logger.WarnEnabled() { + logger.With("context", "foo").Warn().Log("err", "error") + } + + // Output: + // level=warn context=foo err=error +} From 474b18d13a3562cd3ce1cf34e27e591ed05970ee Mon Sep 17 00:00:00 2001 From: Hiroaki Nakamura Date: Sun, 17 Jul 2016 03:48:18 +0900 Subject: [PATCH 2/2] Simplify creation of a level enabled logger --- log/levels/enabled/enabled.go | 127 +++++++++++++++++------------ log/levels/enabled/enabled_test.go | 11 ++- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/log/levels/enabled/enabled.go b/log/levels/enabled/enabled.go index aea4e008d..e6c5a7348 100644 --- a/log/levels/enabled/enabled.go +++ b/log/levels/enabled/enabled.go @@ -1,6 +1,10 @@ package enabled -import "github.com/go-kit/kit/log/levels" +import ( + "errors" + + "github.com/go-kit/kit/log/levels" +) // LevelEnabledLogger provides a wrapper around a logger with a feature // for checking a level is enabled. It has five @@ -17,73 +21,88 @@ type LevelEnabledLogger struct { } // New creates a new level enabled logger, wrapping the passed logger. -func New(logger levels.Levels, option Option) LevelEnabledLogger { - l := LevelEnabledLogger{ - Levels: logger, +// level must be one of debug, info, warning (warn), error, critical (crit) +// or an empty string (which means info). +// It returns an error only when the level value is invalid. +func New(logger levels.Levels, level string) (LevelEnabledLogger, error) { + switch level { + case "debug": + return NewDebug(logger), nil + case "", "info": + return NewInfo(logger), nil + case "warn", "warning": + return NewWarn(logger), nil + case "error": + return NewError(logger), nil + case "crit", "critical": + return NewCrit(logger), nil + default: + return LevelEnabledLogger{}, errors.New("invalid log level") } - option(&l) - return l } -// DebugEnabled returns the debug level is enabled -func (l LevelEnabledLogger) DebugEnabled() bool { return l.debugEnabled } - -// InfoEnabled returns the info level is enabled -func (l LevelEnabledLogger) InfoEnabled() bool { return l.infoEnabled } - -// WarnEnabled returns the warn level is enabled -func (l LevelEnabledLogger) WarnEnabled() bool { return l.warnEnabled } - -// ErrorEnabled returns the error level is enabled -func (l LevelEnabledLogger) ErrorEnabled() bool { return l.errorEnabled } - -// CritEnabled returns the crit level is enabled -func (l LevelEnabledLogger) CritEnabled() bool { return l.critEnabled } - -// Option sets a parameter for level enabled loggers. -type Option func(*LevelEnabledLogger) - -// Debug enables all levels for the level enabled logger. -func Debug() Option { - return func(l *LevelEnabledLogger) { - l.debugEnabled = true - l.infoEnabled = true - l.warnEnabled = true - l.errorEnabled = true - l.critEnabled = true +// NewDebug creates a new debug level enabled logger, wrapping the passed logger. +func NewDebug(logger levels.Levels) LevelEnabledLogger { + return LevelEnabledLogger{ + Levels: logger, + debugEnabled: true, + infoEnabled: true, + warnEnabled: true, + errorEnabled: true, + critEnabled: true, } } -// Info enables info and above levels for the level enabled logger. -func Info() Option { - return func(l *LevelEnabledLogger) { - l.infoEnabled = true - l.warnEnabled = true - l.errorEnabled = true - l.critEnabled = true +// NewInfo creates a new info level enabled logger, wrapping the passed logger. +func NewInfo(logger levels.Levels) LevelEnabledLogger { + return LevelEnabledLogger{ + Levels: logger, + infoEnabled: true, + warnEnabled: true, + errorEnabled: true, + critEnabled: true, } } -// Warn enables warn and above levels for the level enabled logger. -func Warn() Option { - return func(l *LevelEnabledLogger) { - l.warnEnabled = true - l.errorEnabled = true - l.critEnabled = true +// NewWarn creates a new warn level enabled logger, wrapping the passed logger. +func NewWarn(logger levels.Levels) LevelEnabledLogger { + return LevelEnabledLogger{ + Levels: logger, + warnEnabled: true, + errorEnabled: true, + critEnabled: true, } } -// Error enables error and above levels for the level enabled logger. -func Error() Option { - return func(l *LevelEnabledLogger) { - l.errorEnabled = true - l.critEnabled = true +// NewError creates a new error level enabled logger, wrapping the passed logger. +func NewError(logger levels.Levels) LevelEnabledLogger { + return LevelEnabledLogger{ + Levels: logger, + errorEnabled: true, + critEnabled: true, } } -// Crit enables crit level for the level enabled logger. -func Crit() Option { - return func(l *LevelEnabledLogger) { - l.critEnabled = true +// NewCrit creates a new crit level enabled logger, wrapping the passed logger. +func NewCrit(logger levels.Levels) LevelEnabledLogger { + return LevelEnabledLogger{ + Levels: logger, + errorEnabled: true, + critEnabled: true, } } + +// DebugEnabled returns the debug level is enabled +func (l LevelEnabledLogger) DebugEnabled() bool { return l.debugEnabled } + +// InfoEnabled returns the info level is enabled +func (l LevelEnabledLogger) InfoEnabled() bool { return l.infoEnabled } + +// WarnEnabled returns the warn level is enabled +func (l LevelEnabledLogger) WarnEnabled() bool { return l.warnEnabled } + +// ErrorEnabled returns the error level is enabled +func (l LevelEnabledLogger) ErrorEnabled() bool { return l.errorEnabled } + +// CritEnabled returns the crit level is enabled +func (l LevelEnabledLogger) CritEnabled() bool { return l.critEnabled } diff --git a/log/levels/enabled/enabled_test.go b/log/levels/enabled/enabled_test.go index 4fbca22b5..fdd362719 100644 --- a/log/levels/enabled/enabled_test.go +++ b/log/levels/enabled/enabled_test.go @@ -12,7 +12,7 @@ import ( func TestInfoLevel(t *testing.T) { buf := bytes.Buffer{} - logger := enabled.New(levels.New(log.NewLogfmtLogger(&buf)), enabled.Info()) + logger := enabled.NewInfo(levels.New(log.NewLogfmtLogger(&buf))) if logger.DebugEnabled() { logger.Debug().Log("msg", "résumé") // of course you'd want to do this @@ -47,7 +47,14 @@ func TestInfoLevel(t *testing.T) { } func ExampleEnabled() { - logger := enabled.New(levels.New(log.NewLogfmtLogger(os.Stdout)), enabled.Warn()) + logger, err := enabled.New(levels.New(log.NewLogfmtLogger(os.Stdout)), "warn") + if err != nil { + // This happens only when the level is invalid. + // In this example, this never happens as the valid level "warn" is used. + // In a real usage like reading a level from a command line option or a + // config file, you should check this error. + panic(err) + } if logger.DebugEnabled() { logger.Debug().Log("msg", "hello") }