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.
10 loginternal "log/internal"
17 var defaultLogger atomic.Pointer[Logger]
19 var logLoggerLevel LevelVar
21 // SetLogLoggerLevel controls the level for the bridge to the [log] package.
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
29 // slog.SetLogLoggerLevel(slog.LevelDebug)
31 // calls to [Debug] will be passed to the log.Logger.
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
38 // slog.SetLogLoggerLevel(slog.LevelDebug)
40 // A call to [log.Printf] will result in output at level [LevelDebug].
42 // SetLogLoggerLevel returns the previous value.
43 func SetLogLoggerLevel(level Level) (oldLevel Level) {
44 oldLevel = logLoggerLevel.Level()
45 logLoggerLevel.Set(level)
50 defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
53 // Default returns the default [Logger].
54 func Default() *Logger { return defaultLogger.Load() }
56 // SetDefault makes l the default [Logger].
57 // After this call, output from the log package's default Logger
58 // (as with [log.Print], etc.) will be logged using l's Handler,
59 // at a level controlled by [SetLogLoggerLevel].
60 func SetDefault(l *Logger) {
61 defaultLogger.Store(l)
62 // If the default's handler is a defaultHandler, then don't use a handleWriter,
63 // or we'll deadlock as they both try to acquire the log default mutex.
64 // The defaultHandler will use whatever the log default writer is currently
65 // set to, which is correct.
66 // This can occur with SetDefault(Default()).
67 // See TestSetDefault.
68 if _, ok := l.Handler().(*defaultHandler); !ok {
69 capturePC := log.Flags()&(log.Lshortfile|log.Llongfile) != 0
70 log.SetOutput(&handlerWriter{l.Handler(), &logLoggerLevel, capturePC})
71 log.SetFlags(0) // we want just the log message, no time or location
75 // handlerWriter is an io.Writer that calls a Handler.
76 // It is used to link the default log.Logger to the default slog.Logger.
77 type handlerWriter struct {
83 func (w *handlerWriter) Write(buf []byte) (int, error) {
84 level := w.level.Level()
85 if !w.h.Enabled(context.Background(), level) {
89 if !internal.IgnorePC && w.capturePC {
90 // skip [runtime.Callers, w.Write, Logger.Output, log.Print]
92 runtime.Callers(4, pcs[:])
96 // Remove final newline.
97 origLen := len(buf) // Report that the entire buf was written.
98 if len(buf) > 0 && buf[len(buf)-1] == '\n' {
99 buf = buf[:len(buf)-1]
101 r := NewRecord(time.Now(), level, string(buf), pc)
102 return origLen, w.h.Handle(context.Background(), r)
105 // A Logger records structured information about each call to its
106 // Log, Debug, Info, Warn, and Error methods.
107 // For each call, it creates a [Record] and passes it to a [Handler].
109 // To create a new Logger, call [New] or a Logger method
110 // that begins "With".
112 handler Handler // for structured logging
115 func (l *Logger) clone() *Logger {
120 // Handler returns l's Handler.
121 func (l *Logger) Handler() Handler { return l.handler }
123 // With returns a Logger that includes the given attributes
124 // in each output operation. Arguments are converted to
125 // attributes as if by [Logger.Log].
126 func (l *Logger) With(args ...any) *Logger {
131 c.handler = l.handler.WithAttrs(argsToAttrSlice(args))
135 // WithGroup returns a Logger that starts a group, if name is non-empty.
136 // The keys of all attributes added to the Logger will be qualified by the given
137 // name. (How that qualification happens depends on the [Handler.WithGroup]
138 // method of the Logger's Handler.)
140 // If name is empty, WithGroup returns the receiver.
141 func (l *Logger) WithGroup(name string) *Logger {
146 c.handler = l.handler.WithGroup(name)
151 // New creates a new Logger with the given non-nil Handler.
152 func New(h Handler) *Logger {
156 return &Logger{handler: h}
159 // With calls [Logger.With] on the default logger.
160 func With(args ...any) *Logger {
161 return Default().With(args...)
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 {
167 ctx = context.Background()
169 return l.Handler().Enabled(ctx, level)
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)
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.
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
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...)
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...)
198 // Debug logs at [LevelDebug].
199 func (l *Logger) Debug(msg string, args ...any) {
200 l.log(context.Background(), LevelDebug, msg, args...)
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...)
208 // Info logs at [LevelInfo].
209 func (l *Logger) Info(msg string, args ...any) {
210 l.log(context.Background(), LevelInfo, msg, args...)
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...)
218 // Warn logs at [LevelWarn].
219 func (l *Logger) Warn(msg string, args ...any) {
220 l.log(context.Background(), LevelWarn, msg, args...)
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...)
228 // Error logs at [LevelError].
229 func (l *Logger) Error(msg string, args ...any) {
230 l.log(context.Background(), LevelError, msg, args...)
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...)
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) {
246 if !internal.IgnorePC {
248 // skip [runtime.Callers, this function, this function's caller]
249 runtime.Callers(3, pcs[:])
252 r := NewRecord(time.Now(), level, msg, pc)
255 ctx = context.Background()
257 _ = l.Handler().Handle(ctx, r)
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) {
266 if !internal.IgnorePC {
268 // skip [runtime.Callers, this function, this function's caller]
269 runtime.Callers(3, pcs[:])
272 r := NewRecord(time.Now(), level, msg, pc)
275 ctx = context.Background()
277 _ = l.Handler().Handle(ctx, r)
280 // Debug calls [Logger.Debug] on the default logger.
281 func Debug(msg string, args ...any) {
282 Default().log(context.Background(), LevelDebug, msg, args...)
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...)
290 // Info calls [Logger.Info] on the default logger.
291 func Info(msg string, args ...any) {
292 Default().log(context.Background(), LevelInfo, msg, args...)
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...)
300 // Warn calls [Logger.Warn] on the default logger.
301 func Warn(msg string, args ...any) {
302 Default().log(context.Background(), LevelWarn, msg, args...)
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...)
310 // Error calls [Logger.Error] on the default logger.
311 func Error(msg string, args ...any) {
312 Default().log(context.Background(), LevelError, msg, args...)
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...)
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...)
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...)