github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/log/logger.go (about) 1 package log 2 3 import ( 4 "context" 5 "log/slog" 6 "math" 7 "os" 8 "runtime" 9 "time" 10 ) 11 12 const errorKey = "LOG_ERROR" 13 14 const ( 15 legacyLevelCrit = iota 16 legacyLevelError 17 legacyLevelWarn 18 legacyLevelInfo 19 legacyLevelDebug 20 legacyLevelTrace 21 ) 22 23 const ( 24 levelMaxVerbosity slog.Level = math.MinInt 25 LevelTrace slog.Level = -8 26 LevelDebug = slog.LevelDebug 27 LevelInfo = slog.LevelInfo 28 LevelWarn = slog.LevelWarn 29 LevelError = slog.LevelError 30 LevelCrit slog.Level = 12 31 32 // for backward-compatibility 33 LvlTrace = LevelTrace 34 LvlInfo = LevelInfo 35 LvlDebug = LevelDebug 36 ) 37 38 // convert from old Geth verbosity level constants 39 // to levels defined by slog 40 func FromLegacyLevel(lvl int) slog.Level { 41 switch lvl { 42 case legacyLevelCrit: 43 return LevelCrit 44 case legacyLevelError: 45 return slog.LevelError 46 case legacyLevelWarn: 47 return slog.LevelWarn 48 case legacyLevelInfo: 49 return slog.LevelInfo 50 case legacyLevelDebug: 51 return slog.LevelDebug 52 case legacyLevelTrace: 53 return LevelTrace 54 default: 55 break 56 } 57 58 // 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? 59 if lvl > legacyLevelTrace { 60 return LevelTrace 61 } 62 return LevelCrit 63 } 64 65 // LevelAlignedString returns a 5-character string containing the name of a Lvl. 66 func LevelAlignedString(l slog.Level) string { 67 switch l { 68 case LevelTrace: 69 return "TRACE" 70 case slog.LevelDebug: 71 return "DEBUG" 72 case slog.LevelInfo: 73 return "INFO " 74 case slog.LevelWarn: 75 return "WARN " 76 case slog.LevelError: 77 return "ERROR" 78 case LevelCrit: 79 return "CRIT " 80 default: 81 return "unknown level" 82 } 83 } 84 85 // LevelString returns a string containing the name of a Lvl. 86 func LevelString(l slog.Level) string { 87 switch l { 88 case LevelTrace: 89 return "trace" 90 case slog.LevelDebug: 91 return "debug" 92 case slog.LevelInfo: 93 return "info" 94 case slog.LevelWarn: 95 return "warn" 96 case slog.LevelError: 97 return "error" 98 case LevelCrit: 99 return "crit" 100 default: 101 return "unknown" 102 } 103 } 104 105 // A Logger writes key/value pairs to a Handler 106 type Logger interface { 107 // With returns a new Logger that has this logger's attributes plus the given attributes 108 With(ctx ...interface{}) Logger 109 110 // With returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'. 111 New(ctx ...interface{}) Logger 112 113 // Log logs a message at the specified level with context key/value pairs 114 Log(level slog.Level, msg string, ctx ...interface{}) 115 116 // Trace log a message at the trace level with context key/value pairs 117 Trace(msg string, ctx ...interface{}) 118 119 // Debug logs a message at the debug level with context key/value pairs 120 Debug(msg string, ctx ...interface{}) 121 122 // Info logs a message at the info level with context key/value pairs 123 Info(msg string, ctx ...interface{}) 124 125 // Warn logs a message at the warn level with context key/value pairs 126 Warn(msg string, ctx ...interface{}) 127 128 // Error logs a message at the error level with context key/value pairs 129 Error(msg string, ctx ...interface{}) 130 131 // Crit logs a message at the crit level with context key/value pairs, and exits 132 Crit(msg string, ctx ...interface{}) 133 134 // Write logs a message at the specified level 135 Write(level slog.Level, msg string, attrs ...any) 136 137 // Enabled reports whether l emits log records at the given context and level. 138 Enabled(ctx context.Context, level slog.Level) bool 139 140 // Handler returns the underlying handler of the inner logger. 141 Handler() slog.Handler 142 } 143 144 type logger struct { 145 inner *slog.Logger 146 } 147 148 // NewLogger returns a logger with the specified handler set 149 func NewLogger(h slog.Handler) Logger { 150 return &logger{ 151 slog.New(h), 152 } 153 } 154 155 func (l *logger) Handler() slog.Handler { 156 return l.inner.Handler() 157 } 158 159 // Write logs a message at the specified level: 160 func (l *logger) Write(level slog.Level, msg string, attrs ...any) { 161 if !l.inner.Enabled(context.Background(), level) { 162 return 163 } 164 165 var pcs [1]uintptr 166 runtime.Callers(3, pcs[:]) 167 168 if len(attrs)%2 != 0 { 169 attrs = append(attrs, nil, errorKey, "Normalized odd number of arguments by adding nil") 170 } 171 r := slog.NewRecord(time.Now(), level, msg, pcs[0]) 172 r.Add(attrs...) 173 l.inner.Handler().Handle(context.Background(), r) 174 } 175 176 func (l *logger) Log(level slog.Level, msg string, attrs ...any) { 177 l.Write(level, msg, attrs...) 178 } 179 180 func (l *logger) With(ctx ...interface{}) Logger { 181 return &logger{l.inner.With(ctx...)} 182 } 183 184 func (l *logger) New(ctx ...interface{}) Logger { 185 return l.With(ctx...) 186 } 187 188 // Enabled reports whether l emits log records at the given context and level. 189 func (l *logger) Enabled(ctx context.Context, level slog.Level) bool { 190 return l.inner.Enabled(ctx, level) 191 } 192 193 func (l *logger) Trace(msg string, ctx ...interface{}) { 194 l.Write(LevelTrace, msg, ctx...) 195 } 196 197 func (l *logger) Debug(msg string, ctx ...interface{}) { 198 l.Write(slog.LevelDebug, msg, ctx...) 199 } 200 201 func (l *logger) Info(msg string, ctx ...interface{}) { 202 l.Write(slog.LevelInfo, msg, ctx...) 203 } 204 205 func (l *logger) Warn(msg string, ctx ...any) { 206 l.Write(slog.LevelWarn, msg, ctx...) 207 } 208 209 func (l *logger) Error(msg string, ctx ...interface{}) { 210 l.Write(slog.LevelError, msg, ctx...) 211 } 212 213 func (l *logger) Crit(msg string, ctx ...interface{}) { 214 l.Write(LevelCrit, msg, ctx...) 215 os.Exit(1) 216 }