logger.go raw

   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  	"runtime"
  11  	"sync/atomic"
  12  	"time"
  13  
  14  	"golang.org/x/exp/slog/internal"
  15  )
  16  
  17  var defaultLogger atomic.Value
  18  
  19  func init() {
  20  	defaultLogger.Store(New(newDefaultHandler(log.Output)))
  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  // DebugContext logs at LevelDebug with the given context.
 171  func (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.
 177  func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) {
 178  	l.log(ctx, LevelDebug, msg, args...)
 179  }
 180  
 181  // Info logs at LevelInfo.
 182  func (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.
 187  func (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.
 193  func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) {
 194  	l.log(ctx, LevelInfo, msg, args...)
 195  }
 196  
 197  // Warn logs at LevelWarn.
 198  func (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.
 203  func (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.
 209  func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) {
 210  	l.log(ctx, LevelWarn, msg, args...)
 211  }
 212  
 213  // Error logs at LevelError.
 214  func (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.
 219  func (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.
 225  func (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.
 232  func (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.
 252  func (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.
 272  func Debug(msg string, args ...any) {
 273  	Default().log(nil, LevelDebug, msg, args...)
 274  }
 275  
 276  // DebugContext calls Logger.DebugContext on the default logger.
 277  func 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.
 282  func Info(msg string, args ...any) {
 283  	Default().log(nil, LevelInfo, msg, args...)
 284  }
 285  
 286  // InfoContext calls Logger.InfoContext on the default logger.
 287  func 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.
 292  func Warn(msg string, args ...any) {
 293  	Default().log(nil, LevelWarn, msg, args...)
 294  }
 295  
 296  // WarnContext calls Logger.WarnContext on the default logger.
 297  func 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.
 302  func Error(msg string, args ...any) {
 303  	Default().log(nil, LevelError, msg, args...)
 304  }
 305  
 306  // ErrorContext calls Logger.ErrorContext on the default logger.
 307  func 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.
 313  func 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.
 319  func 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.
 325  func 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.
 331  func 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.
 336  func 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.
 341  func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
 342  	Default().logAttrs(ctx, level, msg, attrs...)
 343  }
 344