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
5package slog
6
7import (
8	"context"
9	"log"
10	loginternal "log/internal"
11	"log/slog/internal"
12	"runtime"
13	"sync/atomic"
14	"time"
15)
16
17var defaultLogger atomic.Pointer[Logger]
18
19var 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.
43func SetLogLoggerLevel(level Level) (oldLevel Level) {
44	oldLevel = logLoggerLevel.Level()
45	logLoggerLevel.Set(level)
46	return
47}
48
49func init() {
50	defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
51}
52
53// Default returns the default [Logger].
54func 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].
61func 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.
78type handlerWriter struct {
79	h         Handler
80	level     Leveler
81	capturePC bool
82}
83
84func (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".
112type Logger struct {
113	handler Handler // for structured logging
114}
115
116func (l *Logger) clone() *Logger {
117	c := *l
118	return &c
119}
120
121// Handler returns l's Handler.
122func (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].
127func (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.
142func (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.
152func 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.
160func 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.
165func (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.
175func 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".
189func (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.
194func (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].
199func (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.
204func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
205	l.log(ctx, LevelDebug, msg, args...)
206}
207
208// Info logs at [LevelInfo].
209func (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.
214func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
215	l.log(ctx, LevelInfo, msg, args...)
216}
217
218// Warn logs at [LevelWarn].
219func (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.
224func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
225	l.log(ctx, LevelWarn, msg, args...)
226}
227
228// Error logs at [LevelError].
229func (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.
234func (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.
241func (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.
261func (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.
281func Debug(msg string, args ...any) {
282	Default().log(context.Background(), LevelDebug, msg, args...)
283}
284
285// DebugContext calls [Logger.DebugContext] on the default logger.
286func 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.
291func Info(msg string, args ...any) {
292	Default().log(context.Background(), LevelInfo, msg, args...)
293}
294
295// InfoContext calls [Logger.InfoContext] on the default logger.
296func 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.
301func Warn(msg string, args ...any) {
302	Default().log(context.Background(), LevelWarn, msg, args...)
303}
304
305// WarnContext calls [Logger.WarnContext] on the default logger.
306func 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.
311func Error(msg string, args ...any) {
312	Default().log(context.Background(), LevelError, msg, args...)
313}
314
315// ErrorContext calls [Logger.ErrorContext] on the default logger.
316func 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.
321func 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.
326func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
327	Default().logAttrs(ctx, level, msg, attrs...)
328}
329