github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/log/slog/logger.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package slog 6 7 import ( 8 "context" 9 "log" 10 loginternal "log/internal" 11 "log/slog/internal" 12 "runtime" 13 "sync/atomic" 14 "time" 15 ) 16 17 var defaultLogger atomic.Pointer[Logger] 18 19 var logLoggerLevel LevelVar 20 21 // SetLogLoggerLevel controls the level for the bridge to the [log] package. 22 // 23 // Before [SetDefault] is called, slog top-level logging functions call the default [log.Logger]. 24 // In that mode, SetLogLoggerLevel sets the minimum level for those calls. 25 // By default, the minimum level is Info, so calls to [Debug] 26 // (as well as top-level logging calls at lower levels) 27 // will not be passed to the log.Logger. After calling 28 // 29 // slog.SetLogLoggerLevel(slog.LevelDebug) 30 // 31 // calls to [Debug] will be passed to the log.Logger. 32 // 33 // After [SetDefault] is called, calls to the default [log.Logger] are passed to the 34 // slog default handler. In that mode, 35 // SetLogLoggerLevel sets the level at which those calls are logged. 36 // That is, after calling 37 // 38 // slog.SetLogLoggerLevel(slog.LevelDebug) 39 // 40 // A call to [log.Printf] will result in output at level [LevelDebug]. 41 // 42 // SetLogLoggerLevel returns the previous value. 43 func SetLogLoggerLevel(level Level) (oldLevel Level) { 44 oldLevel = logLoggerLevel.Level() 45 logLoggerLevel.Set(level) 46 return 47 } 48 49 func init() { 50 defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput))) 51 } 52 53 // Default returns the default [Logger]. 54 func Default() *Logger { return defaultLogger.Load() } 55 56 // SetDefault makes l the default [Logger], which is used by 57 // the top-level functions [Info], [Debug] and so on. 58 // After this call, output from the log package's default Logger 59 // (as with [log.Print], etc.) will be logged using l's Handler, 60 // at a level controlled by [SetLogLoggerLevel]. 61 func SetDefault(l *Logger) { 62 defaultLogger.Store(l) 63 // If the default's handler is a defaultHandler, then don't use a handleWriter, 64 // or we'll deadlock as they both try to acquire the log default mutex. 65 // The defaultHandler will use whatever the log default writer is currently 66 // set to, which is correct. 67 // This can occur with SetDefault(Default()). 68 // See TestSetDefault. 69 if _, ok := l.Handler().(*defaultHandler); !ok { 70 capturePC := log.Flags()&(log.Lshortfile|log.Llongfile) != 0 71 log.SetOutput(&handlerWriter{l.Handler(), &logLoggerLevel, capturePC}) 72 log.SetFlags(0) // we want just the log message, no time or location 73 } 74 } 75 76 // handlerWriter is an io.Writer that calls a Handler. 77 // It is used to link the default log.Logger to the default slog.Logger. 78 type handlerWriter struct { 79 h Handler 80 level Leveler 81 capturePC bool 82 } 83 84 func (w *handlerWriter) Write(buf []byte) (int, error) { 85 level := w.level.Level() 86 if !w.h.Enabled(context.Background(), level) { 87 return 0, nil 88 } 89 var pc uintptr 90 if !internal.IgnorePC && w.capturePC { 91 // skip [runtime.Callers, w.Write, Logger.Output, log.Print] 92 var pcs [1]uintptr 93 runtime.Callers(4, pcs[:]) 94 pc = pcs[0] 95 } 96 97 // Remove final newline. 98 origLen := len(buf) // Report that the entire buf was written. 99 if len(buf) > 0 && buf[len(buf)-1] == '\n' { 100 buf = buf[:len(buf)-1] 101 } 102 r := NewRecord(time.Now(), level, string(buf), pc) 103 return origLen, w.h.Handle(context.Background(), r) 104 } 105 106 // A Logger records structured information about each call to its 107 // Log, Debug, Info, Warn, and Error methods. 108 // For each call, it creates a [Record] and passes it to a [Handler]. 109 // 110 // To create a new Logger, call [New] or a Logger method 111 // that begins "With". 112 type Logger struct { 113 handler Handler // for structured logging 114 } 115 116 func (l *Logger) clone() *Logger { 117 c := *l 118 return &c 119 } 120 121 // Handler returns l's Handler. 122 func (l *Logger) Handler() Handler { return l.handler } 123 124 // With returns a Logger that includes the given attributes 125 // in each output operation. Arguments are converted to 126 // attributes as if by [Logger.Log]. 127 func (l *Logger) With(args ...any) *Logger { 128 if len(args) == 0 { 129 return l 130 } 131 c := l.clone() 132 c.handler = l.handler.WithAttrs(argsToAttrSlice(args)) 133 return c 134 } 135 136 // WithGroup returns a Logger that starts a group, if name is non-empty. 137 // The keys of all attributes added to the Logger will be qualified by the given 138 // name. (How that qualification happens depends on the [Handler.WithGroup] 139 // method of the Logger's Handler.) 140 // 141 // If name is empty, WithGroup returns the receiver. 142 func (l *Logger) WithGroup(name string) *Logger { 143 if name == "" { 144 return l 145 } 146 c := l.clone() 147 c.handler = l.handler.WithGroup(name) 148 return c 149 } 150 151 // New creates a new Logger with the given non-nil Handler. 152 func New(h Handler) *Logger { 153 if h == nil { 154 panic("nil Handler") 155 } 156 return &Logger{handler: h} 157 } 158 159 // With calls [Logger.With] on the default logger. 160 func With(args ...any) *Logger { 161 return Default().With(args...) 162 } 163 164 // Enabled reports whether l emits log records at the given context and level. 165 func (l *Logger) Enabled(ctx context.Context, level Level) bool { 166 if ctx == nil { 167 ctx = context.Background() 168 } 169 return l.Handler().Enabled(ctx, level) 170 } 171 172 // NewLogLogger returns a new [log.Logger] such that each call to its Output method 173 // dispatches a Record to the specified handler. The logger acts as a bridge from 174 // the older log API to newer structured logging handlers. 175 func NewLogLogger(h Handler, level Level) *log.Logger { 176 return log.New(&handlerWriter{h, level, true}, "", 0) 177 } 178 179 // Log emits a log record with the current time and the given level and message. 180 // The Record's Attrs consist of the Logger's attributes followed by 181 // the Attrs specified by args. 182 // 183 // The attribute arguments are processed as follows: 184 // - If an argument is an Attr, it is used as is. 185 // - If an argument is a string and this is not the last argument, 186 // the following argument is treated as the value and the two are combined 187 // into an Attr. 188 // - Otherwise, the argument is treated as a value with key "!BADKEY". 189 func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any) { 190 l.log(ctx, level, msg, args...) 191 } 192 193 // LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. 194 func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { 195 l.logAttrs(ctx, level, msg, attrs...) 196 } 197 198 // Debug logs at [LevelDebug]. 199 func (l *Logger) Debug(msg string, args ...any) { 200 l.log(context.Background(), LevelDebug, msg, args...) 201 } 202 203 // DebugContext logs at [LevelDebug] with the given context. 204 func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) { 205 l.log(ctx, LevelDebug, msg, args...) 206 } 207 208 // Info logs at [LevelInfo]. 209 func (l *Logger) Info(msg string, args ...any) { 210 l.log(context.Background(), LevelInfo, msg, args...) 211 } 212 213 // InfoContext logs at [LevelInfo] with the given context. 214 func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) { 215 l.log(ctx, LevelInfo, msg, args...) 216 } 217 218 // Warn logs at [LevelWarn]. 219 func (l *Logger) Warn(msg string, args ...any) { 220 l.log(context.Background(), LevelWarn, msg, args...) 221 } 222 223 // WarnContext logs at [LevelWarn] with the given context. 224 func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) { 225 l.log(ctx, LevelWarn, msg, args...) 226 } 227 228 // Error logs at [LevelError]. 229 func (l *Logger) Error(msg string, args ...any) { 230 l.log(context.Background(), LevelError, msg, args...) 231 } 232 233 // ErrorContext logs at [LevelError] with the given context. 234 func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) { 235 l.log(ctx, LevelError, msg, args...) 236 } 237 238 // log is the low-level logging method for methods that take ...any. 239 // It must always be called directly by an exported logging method 240 // or function, because it uses a fixed call depth to obtain the pc. 241 func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) { 242 if !l.Enabled(ctx, level) { 243 return 244 } 245 var pc uintptr 246 if !internal.IgnorePC { 247 var pcs [1]uintptr 248 // skip [runtime.Callers, this function, this function's caller] 249 runtime.Callers(3, pcs[:]) 250 pc = pcs[0] 251 } 252 r := NewRecord(time.Now(), level, msg, pc) 253 r.Add(args...) 254 if ctx == nil { 255 ctx = context.Background() 256 } 257 _ = l.Handler().Handle(ctx, r) 258 } 259 260 // logAttrs is like [Logger.log], but for methods that take ...Attr. 261 func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { 262 if !l.Enabled(ctx, level) { 263 return 264 } 265 var pc uintptr 266 if !internal.IgnorePC { 267 var pcs [1]uintptr 268 // skip [runtime.Callers, this function, this function's caller] 269 runtime.Callers(3, pcs[:]) 270 pc = pcs[0] 271 } 272 r := NewRecord(time.Now(), level, msg, pc) 273 r.AddAttrs(attrs...) 274 if ctx == nil { 275 ctx = context.Background() 276 } 277 _ = l.Handler().Handle(ctx, r) 278 } 279 280 // Debug calls [Logger.Debug] on the default logger. 281 func Debug(msg string, args ...any) { 282 Default().log(context.Background(), LevelDebug, msg, args...) 283 } 284 285 // DebugContext calls [Logger.DebugContext] on the default logger. 286 func DebugContext(ctx context.Context, msg string, args ...any) { 287 Default().log(ctx, LevelDebug, msg, args...) 288 } 289 290 // Info calls [Logger.Info] on the default logger. 291 func Info(msg string, args ...any) { 292 Default().log(context.Background(), LevelInfo, msg, args...) 293 } 294 295 // InfoContext calls [Logger.InfoContext] on the default logger. 296 func InfoContext(ctx context.Context, msg string, args ...any) { 297 Default().log(ctx, LevelInfo, msg, args...) 298 } 299 300 // Warn calls [Logger.Warn] on the default logger. 301 func Warn(msg string, args ...any) { 302 Default().log(context.Background(), LevelWarn, msg, args...) 303 } 304 305 // WarnContext calls [Logger.WarnContext] on the default logger. 306 func WarnContext(ctx context.Context, msg string, args ...any) { 307 Default().log(ctx, LevelWarn, msg, args...) 308 } 309 310 // Error calls [Logger.Error] on the default logger. 311 func Error(msg string, args ...any) { 312 Default().log(context.Background(), LevelError, msg, args...) 313 } 314 315 // ErrorContext calls [Logger.ErrorContext] on the default logger. 316 func ErrorContext(ctx context.Context, msg string, args ...any) { 317 Default().log(ctx, LevelError, msg, args...) 318 } 319 320 // Log calls [Logger.Log] on the default logger. 321 func Log(ctx context.Context, level Level, msg string, args ...any) { 322 Default().log(ctx, level, msg, args...) 323 } 324 325 // LogAttrs calls [Logger.LogAttrs] on the default logger. 326 func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) { 327 Default().logAttrs(ctx, level, msg, attrs...) 328 }