add Write method to Logger interface to allow expressing all operations in the root logger in terms of Logger

This commit is contained in:
Jared Wasinger 2023-11-22 13:50:26 +08:00
parent 98166316b9
commit eb04be1635
4 changed files with 27 additions and 32 deletions

View file

@ -102,6 +102,8 @@ func (l *logger) Inner() *slog.Logger {
return l.l.Inner() return l.l.Inner()
} }
func (l *logger) Write(level slog.Level, msg string, ctx ...interface{}) {}
func (l *logger) Trace(msg string, ctx ...interface{}) { func (l *logger) Trace(msg string, ctx ...interface{}) {
l.t.Helper() l.t.Helper()
l.mu.Lock() l.mu.Lock()

View file

@ -212,6 +212,8 @@ func builtinReplace(_ []string, attr slog.Attr, logfmt bool) slog.Attr {
} else { } else {
attr.Value = slog.StringValue(v.Dec()) attr.Value = slog.StringValue(v.Dec())
} }
case fmt.Stringer:
attr.Value = slog.StringValue(v.String())
} }
return attr return attr
} }

View file

@ -136,6 +136,9 @@ type Logger interface {
// Inner returns the underlying slog logger that is wrapped // Inner returns the underlying slog logger that is wrapped
Inner() *slog.Logger Inner() *slog.Logger
// Write logs a message at the specified level
Write(level slog.Level, msg string, attrs ...any)
} }
type logger struct { type logger struct {
@ -155,7 +158,7 @@ func (l *logger) Inner() *slog.Logger {
} }
// write logs a message at the specified level: // write logs a message at the specified level:
func (l *logger) write(level slog.Level, msg string, attrs ...any) { func (l *logger) Write(level slog.Level, msg string, attrs ...any) {
if !l.inner.Enabled(context.Background(), level) { if !l.inner.Enabled(context.Background(), level) {
return return
} }
@ -192,7 +195,7 @@ func (l *logger) write(level slog.Level, msg string, attrs ...any) {
} }
func (l *logger) Log(level slog.Level, msg string, attrs ...any) { func (l *logger) Log(level slog.Level, msg string, attrs ...any) {
l.write(level, msg, attrs...) l.Write(level, msg, attrs...)
} }
func (l *logger) With(ctx ...interface{}) Logger { func (l *logger) With(ctx ...interface{}) Logger {
@ -204,26 +207,26 @@ func (l *logger) New(ctx ...interface{}) Logger {
} }
func (l *logger) Trace(msg string, ctx ...interface{}) { func (l *logger) Trace(msg string, ctx ...interface{}) {
l.write(LevelTrace, msg, ctx...) l.Write(LevelTrace, msg, ctx...)
} }
func (l *logger) Debug(msg string, ctx ...interface{}) { func (l *logger) Debug(msg string, ctx ...interface{}) {
l.write(slog.LevelDebug, msg, ctx...) l.Write(slog.LevelDebug, msg, ctx...)
} }
func (l *logger) Info(msg string, ctx ...interface{}) { func (l *logger) Info(msg string, ctx ...interface{}) {
l.write(slog.LevelInfo, msg, ctx...) l.Write(slog.LevelInfo, msg, ctx...)
} }
func (l *logger) Warn(msg string, ctx ...any) { func (l *logger) Warn(msg string, ctx ...any) {
l.write(slog.LevelWarn, msg, ctx...) l.Write(slog.LevelWarn, msg, ctx...)
} }
func (l *logger) Error(msg string, ctx ...interface{}) { func (l *logger) Error(msg string, ctx ...interface{}) {
l.write(slog.LevelError, msg, ctx...) l.Write(slog.LevelError, msg, ctx...)
} }
func (l *logger) Crit(msg string, ctx ...interface{}) { func (l *logger) Crit(msg string, ctx ...interface{}) {
l.write(LevelCrit, msg, ctx...) l.Write(LevelCrit, msg, ctx...)
os.Exit(1) os.Exit(1)
} }

View file

@ -2,42 +2,30 @@ package log
import ( import (
"os" "os"
"sync"
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
) )
var ( var root Logger
rootMu sync.Mutex
root logger
)
func init() { func init() {
defaultLogger := &logger{slog.New(DiscardHandler())} defaultLogger := &logger{slog.New(DiscardHandler())}
SetDefault(defaultLogger) SetDefault(defaultLogger)
} }
// SetDefault sets the default global logger
func SetDefault(l Logger) { func SetDefault(l Logger) {
rootMu.Lock() root = l
defer rootMu.Unlock()
root := l
slog.SetDefault(root.Inner()) slog.SetDefault(root.Inner())
} }
// Root returns the root logger // Root returns the root logger
func Root() Logger { func Root() Logger {
return rootLogger() return Root()
}
func rootLogger() *logger {
rootMu.Lock()
defer rootMu.Unlock()
res := root
return &res
} }
// The following functions bypass the exported logger methods (logger.Debug, // The following functions bypass the exported logger methods (logger.Debug,
// etc.) to keep the call depth the same for all paths to logger.write so // etc.) to keep the call depth the same for all paths to logger.Write so
// runtime.Caller(2) always refers to the call site in client code. // runtime.Caller(2) always refers to the call site in client code.
// Trace is a convenient alias for Root().Trace // Trace is a convenient alias for Root().Trace
@ -50,7 +38,7 @@ func rootLogger() *logger {
// log.Trace("msg", "key1", val1) // log.Trace("msg", "key1", val1)
// log.Trace("msg", "key1", val1, "key2", val2) // log.Trace("msg", "key1", val1, "key2", val2)
func Trace(msg string, ctx ...interface{}) { func Trace(msg string, ctx ...interface{}) {
rootLogger().write(LevelTrace, msg, ctx...) Root().Write(LevelTrace, msg, ctx...)
} }
// Debug is a convenient alias for Root().Debug // Debug is a convenient alias for Root().Debug
@ -63,7 +51,7 @@ func Trace(msg string, ctx ...interface{}) {
// log.Debug("msg", "key1", val1) // log.Debug("msg", "key1", val1)
// log.Debug("msg", "key1", val1, "key2", val2) // log.Debug("msg", "key1", val1, "key2", val2)
func Debug(msg string, ctx ...interface{}) { func Debug(msg string, ctx ...interface{}) {
rootLogger().write(slog.LevelDebug, msg, ctx...) Root().Write(slog.LevelDebug, msg, ctx...)
} }
// Info is a convenient alias for Root().Info // Info is a convenient alias for Root().Info
@ -76,7 +64,7 @@ func Debug(msg string, ctx ...interface{}) {
// log.Info("msg", "key1", val1) // log.Info("msg", "key1", val1)
// log.Info("msg", "key1", val1, "key2", val2) // log.Info("msg", "key1", val1, "key2", val2)
func Info(msg string, ctx ...interface{}) { func Info(msg string, ctx ...interface{}) {
rootLogger().write(slog.LevelInfo, msg, ctx...) Root().Write(slog.LevelInfo, msg, ctx...)
} }
// Warn is a convenient alias for Root().Warn // Warn is a convenient alias for Root().Warn
@ -89,7 +77,7 @@ func Info(msg string, ctx ...interface{}) {
// log.Warn("msg", "key1", val1) // log.Warn("msg", "key1", val1)
// log.Warn("msg", "key1", val1, "key2", val2) // log.Warn("msg", "key1", val1, "key2", val2)
func Warn(msg string, ctx ...interface{}) { func Warn(msg string, ctx ...interface{}) {
rootLogger().write(slog.LevelWarn, msg, ctx...) Root().Write(slog.LevelWarn, msg, ctx...)
} }
// Error is a convenient alias for Root().Error // Error is a convenient alias for Root().Error
@ -102,7 +90,7 @@ func Warn(msg string, ctx ...interface{}) {
// log.Error("msg", "key1", val1) // log.Error("msg", "key1", val1)
// log.Error("msg", "key1", val1, "key2", val2) // log.Error("msg", "key1", val1, "key2", val2)
func Error(msg string, ctx ...interface{}) { func Error(msg string, ctx ...interface{}) {
rootLogger().write(slog.LevelError, msg, ctx...) Root().Write(slog.LevelError, msg, ctx...)
} }
// Crit is a convenient alias for Root().Crit // Crit is a convenient alias for Root().Crit
@ -115,12 +103,12 @@ func Error(msg string, ctx ...interface{}) {
// log.Crit("msg", "key1", val1) // log.Crit("msg", "key1", val1)
// log.Crit("msg", "key1", val1, "key2", val2) // log.Crit("msg", "key1", val1, "key2", val2)
func Crit(msg string, ctx ...interface{}) { func Crit(msg string, ctx ...interface{}) {
rootLogger().write(LevelCrit, msg, ctx...) Root().Write(LevelCrit, msg, ctx...)
os.Exit(1) os.Exit(1)
} }
// New returns a new logger with the given context. // New returns a new logger with the given context.
// New is a convenient alias for Root().New // New is a convenient alias for Root().New
func New(ctx ...interface{}) Logger { func New(ctx ...interface{}) Logger {
return rootLogger().With(ctx...) return Root().With(ctx...)
} }