1
0
Fork 0
forked from forks/go-ethereum
go-ethereum-modded-tocallarg/log/root.go
Stephen Buttolph 51177ed8c5
log: fix SetDefault for custom loggers (#31368)
Currently, even though it takes in a `Logger` interface,
`log.SetDefualt` enforces that the concrete type of the provided logger
is `*logger` because:
1. in `init` `root.Store` is called with a `*logger`
2. `atomic.Value` panics if the concrete type provided in `Store` is not
consistent across calls.
([ref](https://pkg.go.dev/sync/atomic#Value.Store))

> All calls to Store for a given Value must use values of the same
concrete type.

This PR changes to use `sync.RWMutex` and adds a test that panics on
`master`.
2025-03-14 16:56:53 +01:00

124 lines
2.8 KiB
Go

package log
import (
"log/slog"
"os"
"sync"
)
var (
rootLock sync.RWMutex
root Logger
)
func init() {
root = &logger{slog.New(DiscardHandler())}
}
// SetDefault sets the default global logger
func SetDefault(l Logger) {
rootLock.Lock()
defer rootLock.Unlock()
root = l
if lg, ok := l.(*logger); ok {
slog.SetDefault(lg.inner)
}
}
// Root returns the root logger
func Root() Logger {
rootLock.RLock()
defer rootLock.RUnlock()
return root
}
// 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
// runtime.Caller(2) always refers to the call site in client code.
// Trace is a convenient alias for Root().Trace
//
// Log a message at the trace level with context key/value pairs
//
// # Usage
//
// log.Trace("msg")
// log.Trace("msg", "key1", val1)
// log.Trace("msg", "key1", val1, "key2", val2)
func Trace(msg string, ctx ...interface{}) {
Root().Write(LevelTrace, msg, ctx...)
}
// Debug is a convenient alias for Root().Debug
//
// Log a message at the debug level with context key/value pairs
//
// # Usage Examples
//
// log.Debug("msg")
// log.Debug("msg", "key1", val1)
// log.Debug("msg", "key1", val1, "key2", val2)
func Debug(msg string, ctx ...interface{}) {
Root().Write(slog.LevelDebug, msg, ctx...)
}
// Info is a convenient alias for Root().Info
//
// Log a message at the info level with context key/value pairs
//
// # Usage Examples
//
// log.Info("msg")
// log.Info("msg", "key1", val1)
// log.Info("msg", "key1", val1, "key2", val2)
func Info(msg string, ctx ...interface{}) {
Root().Write(slog.LevelInfo, msg, ctx...)
}
// Warn is a convenient alias for Root().Warn
//
// Log a message at the warn level with context key/value pairs
//
// # Usage Examples
//
// log.Warn("msg")
// log.Warn("msg", "key1", val1)
// log.Warn("msg", "key1", val1, "key2", val2)
func Warn(msg string, ctx ...interface{}) {
Root().Write(slog.LevelWarn, msg, ctx...)
}
// Error is a convenient alias for Root().Error
//
// Log a message at the error level with context key/value pairs
//
// # Usage Examples
//
// log.Error("msg")
// log.Error("msg", "key1", val1)
// log.Error("msg", "key1", val1, "key2", val2)
func Error(msg string, ctx ...interface{}) {
Root().Write(slog.LevelError, msg, ctx...)
}
// Crit is a convenient alias for Root().Crit
//
// Log a message at the crit level with context key/value pairs, and then exit.
//
// # Usage Examples
//
// log.Crit("msg")
// log.Crit("msg", "key1", val1)
// log.Crit("msg", "key1", val1, "key2", val2)
func Crit(msg string, ctx ...interface{}) {
Root().Write(LevelCrit, msg, ctx...)
os.Exit(1)
}
// New returns a new logger with the given context.
// New is a convenient alias for Root().New
func New(ctx ...interface{}) Logger {
return Root().With(ctx...)
}