|
|
|
package log
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"log/slog"
|
|
|
|
"math"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const errorKey = "LOG_ERROR"
|
|
|
|
|
|
|
|
const (
|
|
|
|
legacyLevelCrit = iota
|
|
|
|
legacyLevelError
|
|
|
|
legacyLevelWarn
|
|
|
|
legacyLevelInfo
|
|
|
|
legacyLevelDebug
|
|
|
|
legacyLevelTrace
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
levelMaxVerbosity slog.Level = math.MinInt
|
|
|
|
LevelTrace slog.Level = -8
|
|
|
|
LevelDebug = slog.LevelDebug
|
|
|
|
LevelInfo = slog.LevelInfo
|
|
|
|
LevelWarn = slog.LevelWarn
|
|
|
|
LevelError = slog.LevelError
|
|
|
|
LevelCrit slog.Level = 12
|
|
|
|
|
|
|
|
// for backward-compatibility
|
|
|
|
LvlTrace = LevelTrace
|
|
|
|
LvlInfo = LevelInfo
|
|
|
|
LvlDebug = LevelDebug
|
|
|
|
)
|
|
|
|
|
|
|
|
// FromLegacyLevel converts from old Geth verbosity level constants
|
|
|
|
// to levels defined by slog
|
|
|
|
func FromLegacyLevel(lvl int) slog.Level {
|
|
|
|
switch lvl {
|
|
|
|
case legacyLevelCrit:
|
|
|
|
return LevelCrit
|
|
|
|
case legacyLevelError:
|
|
|
|
return slog.LevelError
|
|
|
|
case legacyLevelWarn:
|
|
|
|
return slog.LevelWarn
|
|
|
|
case legacyLevelInfo:
|
|
|
|
return slog.LevelInfo
|
|
|
|
case legacyLevelDebug:
|
|
|
|
return slog.LevelDebug
|
|
|
|
case legacyLevelTrace:
|
|
|
|
return LevelTrace
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: should we allow use of custom levels or force them to match existing max/min if they fall outside the range as I am doing here?
|
|
|
|
if lvl > legacyLevelTrace {
|
|
|
|
return LevelTrace
|
|
|
|
}
|
|
|
|
return LevelCrit
|
|
|
|
}
|
|
|
|
|
|
|
|
// LevelAlignedString returns a 5-character string containing the name of a Lvl.
|
|
|
|
func LevelAlignedString(l slog.Level) string {
|
|
|
|
switch l {
|
|
|
|
case LevelTrace:
|
|
|
|
return "TRACE"
|
|
|
|
case slog.LevelDebug:
|
|
|
|
return "DEBUG"
|
|
|
|
case slog.LevelInfo:
|
|
|
|
return "INFO "
|
|
|
|
case slog.LevelWarn:
|
|
|
|
return "WARN "
|
|
|
|
case slog.LevelError:
|
|
|
|
return "ERROR"
|
|
|
|
case LevelCrit:
|
|
|
|
return "CRIT "
|
|
|
|
default:
|
|
|
|
return "unknown level"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// LevelString returns a string containing the name of a Lvl.
|
|
|
|
func LevelString(l slog.Level) string {
|
|
|
|
switch l {
|
|
|
|
case LevelTrace:
|
|
|
|
return "trace"
|
|
|
|
case slog.LevelDebug:
|
|
|
|
return "debug"
|
|
|
|
case slog.LevelInfo:
|
|
|
|
return "info"
|
|
|
|
case slog.LevelWarn:
|
|
|
|
return "warn"
|
|
|
|
case slog.LevelError:
|
|
|
|
return "error"
|
|
|
|
case LevelCrit:
|
|
|
|
return "crit"
|
|
|
|
default:
|
|
|
|
return "unknown"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A Logger writes key/value pairs to a Handler
|
|
|
|
type Logger interface {
|
|
|
|
// With returns a new Logger that has this logger's attributes plus the given attributes
|
|
|
|
With(ctx ...interface{}) Logger
|
|
|
|
|
|
|
|
// New returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'.
|
|
|
|
New(ctx ...interface{}) Logger
|
|
|
|
|
|
|
|
// Log logs a message at the specified level with context key/value pairs
|
|
|
|
Log(level slog.Level, msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Trace log a message at the trace level with context key/value pairs
|
|
|
|
Trace(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Debug logs a message at the debug level with context key/value pairs
|
|
|
|
Debug(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Info logs a message at the info level with context key/value pairs
|
|
|
|
Info(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Warn logs a message at the warn level with context key/value pairs
|
|
|
|
Warn(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Error logs a message at the error level with context key/value pairs
|
|
|
|
Error(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Crit logs a message at the crit level with context key/value pairs, and exits
|
|
|
|
Crit(msg string, ctx ...interface{})
|
|
|
|
|
|
|
|
// Write logs a message at the specified level
|
|
|
|
Write(level slog.Level, msg string, attrs ...any)
|
log: remove lazy, remove unused interfaces, unexport methods (#28622)
This change
- Removes interface `log.Format`,
- Removes method `log.FormatFunc`,
- unexports `TerminalHandler.TerminalFormat` formatting methods (renamed to `TerminalHandler.format`)
- removes the notion of `log.Lazy` values
The lazy handler was useful in the old log package, since it
could defer the evaluation of costly attributes until later in the
log pipeline: thus, if the logging was done at 'Trace', we could
skip evaluation if logging only was set to 'Info'.
With the move to slog, this way of deferring evaluation is no longer
needed, since slog introduced 'Enabled': the caller can thus do
the evaluate-or-not decision at the callsite, which is much more
straight-forward than dealing with lazy reflect-based evaluation.
Also, lazy evaluation would not work with 'native' slog, as in, these
two statements would be evaluated differently:
```golang
log.Info("foo", "my lazy", lazyObj)
slog.Info("foo", "my lazy", lazyObj)
```
11 months ago
|
|
|
|
|
|
|
// Enabled reports whether l emits log records at the given context and level.
|
|
|
|
Enabled(ctx context.Context, level slog.Level) bool
|
|
|
|
|
|
|
|
// Handler returns the underlying handler of the inner logger.
|
|
|
|
Handler() slog.Handler
|
|
|
|
}
|
|
|
|
|
|
|
|
type logger struct {
|
|
|
|
inner *slog.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewLogger returns a logger with the specified handler set
|
|
|
|
func NewLogger(h slog.Handler) Logger {
|
|
|
|
return &logger{
|
|
|
|
slog.New(h),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Handler() slog.Handler {
|
|
|
|
return l.inner.Handler()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write logs a message at the specified level.
|
|
|
|
func (l *logger) Write(level slog.Level, msg string, attrs ...any) {
|
|
|
|
if !l.inner.Enabled(context.Background(), level) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var pcs [1]uintptr
|
|
|
|
runtime.Callers(3, pcs[:])
|
|
|
|
|
|
|
|
if len(attrs)%2 != 0 {
|
|
|
|
attrs = append(attrs, nil, errorKey, "Normalized odd number of arguments by adding nil")
|
|
|
|
}
|
|
|
|
r := slog.NewRecord(time.Now(), level, msg, pcs[0])
|
|
|
|
r.Add(attrs...)
|
|
|
|
l.inner.Handler().Handle(context.Background(), r)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Log(level slog.Level, msg string, attrs ...any) {
|
|
|
|
l.Write(level, msg, attrs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) With(ctx ...interface{}) Logger {
|
|
|
|
return &logger{l.inner.With(ctx...)}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) New(ctx ...interface{}) Logger {
|
|
|
|
return l.With(ctx...)
|
|
|
|
}
|
|
|
|
|
log: remove lazy, remove unused interfaces, unexport methods (#28622)
This change
- Removes interface `log.Format`,
- Removes method `log.FormatFunc`,
- unexports `TerminalHandler.TerminalFormat` formatting methods (renamed to `TerminalHandler.format`)
- removes the notion of `log.Lazy` values
The lazy handler was useful in the old log package, since it
could defer the evaluation of costly attributes until later in the
log pipeline: thus, if the logging was done at 'Trace', we could
skip evaluation if logging only was set to 'Info'.
With the move to slog, this way of deferring evaluation is no longer
needed, since slog introduced 'Enabled': the caller can thus do
the evaluate-or-not decision at the callsite, which is much more
straight-forward than dealing with lazy reflect-based evaluation.
Also, lazy evaluation would not work with 'native' slog, as in, these
two statements would be evaluated differently:
```golang
log.Info("foo", "my lazy", lazyObj)
slog.Info("foo", "my lazy", lazyObj)
```
11 months ago
|
|
|
// Enabled reports whether l emits log records at the given context and level.
|
|
|
|
func (l *logger) Enabled(ctx context.Context, level slog.Level) bool {
|
|
|
|
return l.inner.Enabled(ctx, level)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Trace(msg string, ctx ...interface{}) {
|
|
|
|
l.Write(LevelTrace, msg, ctx...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Debug(msg string, ctx ...interface{}) {
|
|
|
|
l.Write(slog.LevelDebug, msg, ctx...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Info(msg string, ctx ...interface{}) {
|
|
|
|
l.Write(slog.LevelInfo, msg, ctx...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Warn(msg string, ctx ...any) {
|
|
|
|
l.Write(slog.LevelWarn, msg, ctx...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Error(msg string, ctx ...interface{}) {
|
|
|
|
l.Write(slog.LevelError, msg, ctx...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *logger) Crit(msg string, ctx ...interface{}) {
|
|
|
|
l.Write(LevelCrit, msg, ctx...)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|