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