logger.go

  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	"runtime"
 11	"sync/atomic"
 12	"time"
 13
 14	"golang.org/x/exp/slog/internal"
 15)
 16
 17var defaultLogger atomic.Value
 18
 19func init() {
 20	defaultLogger.Store(New(newDefaultHandler(log.Output)))
 21}
 22
 23// Default returns the default Logger.
 24func 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.
 29func 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.
 46type handlerWriter struct {
 47	h         Handler
 48	level     Level
 49	capturePC bool
 50}
 51
 52func (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".
 79type Logger struct {
 80	handler Handler // for structured logging
 81}
 82
 83func (l *Logger) clone() *Logger {
 84	c := *l
 85	return &c
 86}
 87
 88// Handler returns l's Handler.
 89func (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.
 97func (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.
111func (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.
119func 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.
127func 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.
132func (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.
142func 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".
156func (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.
161func (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.
166func (l *Logger) Debug(msg string, args ...any) {
167	l.log(nil, LevelDebug, msg, args...)
168}
169
170// DebugContext logs at LevelDebug with the given context.
171func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
172	l.log(ctx, LevelDebug, msg, args...)
173}
174
175// DebugCtx logs at LevelDebug with the given context.
176// Deprecated: Use Logger.DebugContext.
177func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) {
178	l.log(ctx, LevelDebug, msg, args...)
179}
180
181// Info logs at LevelInfo.
182func (l *Logger) Info(msg string, args ...any) {
183	l.log(nil, LevelInfo, msg, args...)
184}
185
186// InfoContext logs at LevelInfo with the given context.
187func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
188	l.log(ctx, LevelInfo, msg, args...)
189}
190
191// InfoCtx logs at LevelInfo with the given context.
192// Deprecated: Use Logger.InfoContext.
193func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) {
194	l.log(ctx, LevelInfo, msg, args...)
195}
196
197// Warn logs at LevelWarn.
198func (l *Logger) Warn(msg string, args ...any) {
199	l.log(nil, LevelWarn, msg, args...)
200}
201
202// WarnContext logs at LevelWarn with the given context.
203func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
204	l.log(ctx, LevelWarn, msg, args...)
205}
206
207// WarnCtx logs at LevelWarn with the given context.
208// Deprecated: Use Logger.WarnContext.
209func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) {
210	l.log(ctx, LevelWarn, msg, args...)
211}
212
213// Error logs at LevelError.
214func (l *Logger) Error(msg string, args ...any) {
215	l.log(nil, LevelError, msg, args...)
216}
217
218// ErrorContext logs at LevelError with the given context.
219func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) {
220	l.log(ctx, LevelError, msg, args...)
221}
222
223// ErrorCtx logs at LevelError with the given context.
224// Deprecated: Use Logger.ErrorContext.
225func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) {
226	l.log(ctx, LevelError, msg, args...)
227}
228
229// log is the low-level logging method for methods that take ...any.
230// It must always be called directly by an exported logging method
231// or function, because it uses a fixed call depth to obtain the pc.
232func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) {
233	if !l.Enabled(ctx, level) {
234		return
235	}
236	var pc uintptr
237	if !internal.IgnorePC {
238		var pcs [1]uintptr
239		// skip [runtime.Callers, this function, this function's caller]
240		runtime.Callers(3, pcs[:])
241		pc = pcs[0]
242	}
243	r := NewRecord(time.Now(), level, msg, pc)
244	r.Add(args...)
245	if ctx == nil {
246		ctx = context.Background()
247	}
248	_ = l.Handler().Handle(ctx, r)
249}
250
251// logAttrs is like [Logger.log], but for methods that take ...Attr.
252func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
253	if !l.Enabled(ctx, level) {
254		return
255	}
256	var pc uintptr
257	if !internal.IgnorePC {
258		var pcs [1]uintptr
259		// skip [runtime.Callers, this function, this function's caller]
260		runtime.Callers(3, pcs[:])
261		pc = pcs[0]
262	}
263	r := NewRecord(time.Now(), level, msg, pc)
264	r.AddAttrs(attrs...)
265	if ctx == nil {
266		ctx = context.Background()
267	}
268	_ = l.Handler().Handle(ctx, r)
269}
270
271// Debug calls Logger.Debug on the default logger.
272func Debug(msg string, args ...any) {
273	Default().log(nil, LevelDebug, msg, args...)
274}
275
276// DebugContext calls Logger.DebugContext on the default logger.
277func DebugContext(ctx context.Context, msg string, args ...any) {
278	Default().log(ctx, LevelDebug, msg, args...)
279}
280
281// Info calls Logger.Info on the default logger.
282func Info(msg string, args ...any) {
283	Default().log(nil, LevelInfo, msg, args...)
284}
285
286// InfoContext calls Logger.InfoContext on the default logger.
287func InfoContext(ctx context.Context, msg string, args ...any) {
288	Default().log(ctx, LevelInfo, msg, args...)
289}
290
291// Warn calls Logger.Warn on the default logger.
292func Warn(msg string, args ...any) {
293	Default().log(nil, LevelWarn, msg, args...)
294}
295
296// WarnContext calls Logger.WarnContext on the default logger.
297func WarnContext(ctx context.Context, msg string, args ...any) {
298	Default().log(ctx, LevelWarn, msg, args...)
299}
300
301// Error calls Logger.Error on the default logger.
302func Error(msg string, args ...any) {
303	Default().log(nil, LevelError, msg, args...)
304}
305
306// ErrorContext calls Logger.ErrorContext on the default logger.
307func ErrorContext(ctx context.Context, msg string, args ...any) {
308	Default().log(ctx, LevelError, msg, args...)
309}
310
311// DebugCtx calls Logger.DebugContext on the default logger.
312// Deprecated: call DebugContext.
313func DebugCtx(ctx context.Context, msg string, args ...any) {
314	Default().log(ctx, LevelDebug, msg, args...)
315}
316
317// InfoCtx calls Logger.InfoContext on the default logger.
318// Deprecated: call InfoContext.
319func InfoCtx(ctx context.Context, msg string, args ...any) {
320	Default().log(ctx, LevelInfo, msg, args...)
321}
322
323// WarnCtx calls Logger.WarnContext on the default logger.
324// Deprecated: call WarnContext.
325func WarnCtx(ctx context.Context, msg string, args ...any) {
326	Default().log(ctx, LevelWarn, msg, args...)
327}
328
329// ErrorCtx calls Logger.ErrorContext on the default logger.
330// Deprecated: call ErrorContext.
331func ErrorCtx(ctx context.Context, msg string, args ...any) {
332	Default().log(ctx, LevelError, msg, args...)
333}
334
335// Log calls Logger.Log on the default logger.
336func Log(ctx context.Context, level Level, msg string, args ...any) {
337	Default().log(ctx, level, msg, args...)
338}
339
340// LogAttrs calls Logger.LogAttrs on the default logger.
341func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
342	Default().logAttrs(ctx, level, msg, attrs...)
343}