]> Cypherpunks.ru repositories - gostls13.git/blob - src/log/slog/logger.go
f03aeec295cb08ea71fb2958d03c09812a1a09e5
[gostls13.git] / src / log / slog / 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
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.Pointer[Logger]
18
19 var 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.
43 func SetLogLoggerLevel(level Level) (oldLevel Level) {
44         oldLevel = logLoggerLevel.Level()
45         logLoggerLevel.Set(level)
46         return
47 }
48
49 func init() {
50         defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
51 }
52
53 // Default returns the default [Logger].
54 func Default() *Logger { return defaultLogger.Load() }
55
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
72         }
73 }
74
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 {
78         h         Handler
79         level     Leveler
80         capturePC bool
81 }
82
83 func (w *handlerWriter) Write(buf []byte) (int, error) {
84         level := w.level.Level()
85         if !w.h.Enabled(context.Background(), level) {
86                 return 0, nil
87         }
88         var pc uintptr
89         if !internal.IgnorePC && w.capturePC {
90                 // skip [runtime.Callers, w.Write, Logger.Output, log.Print]
91                 var pcs [1]uintptr
92                 runtime.Callers(4, pcs[:])
93                 pc = pcs[0]
94         }
95
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]
100         }
101         r := NewRecord(time.Now(), level, string(buf), pc)
102         return origLen, w.h.Handle(context.Background(), r)
103 }
104
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].
108 //
109 // To create a new Logger, call [New] or a Logger method
110 // that begins "With".
111 type Logger struct {
112         handler Handler // for structured logging
113 }
114
115 func (l *Logger) clone() *Logger {
116         c := *l
117         return &c
118 }
119
120 // Handler returns l's Handler.
121 func (l *Logger) Handler() Handler { return l.handler }
122
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 {
127         if len(args) == 0 {
128                 return l
129         }
130         c := l.clone()
131         c.handler = l.handler.WithAttrs(argsToAttrSlice(args))
132         return c
133 }
134
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.)
139 //
140 // If name is empty, WithGroup returns the receiver.
141 func (l *Logger) WithGroup(name string) *Logger {
142         if name == "" {
143                 return l
144         }
145         c := l.clone()
146         c.handler = l.handler.WithGroup(name)
147         return c
148
149 }
150
151 // New creates a new Logger with the given non-nil Handler.
152 func 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.
160 func 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.
165 func (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.
175 func 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".
189 func (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.
194 func (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].
199 func (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.
204 func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
205         l.log(ctx, LevelDebug, msg, args...)
206 }
207
208 // Info logs at [LevelInfo].
209 func (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.
214 func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
215         l.log(ctx, LevelInfo, msg, args...)
216 }
217
218 // Warn logs at [LevelWarn].
219 func (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.
224 func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
225         l.log(ctx, LevelWarn, msg, args...)
226 }
227
228 // Error logs at [LevelError].
229 func (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.
234 func (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.
241 func (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.
261 func (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.
281 func Debug(msg string, args ...any) {
282         Default().log(context.Background(), LevelDebug, msg, args...)
283 }
284
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...)
288 }
289
290 // Info calls [Logger.Info] on the default logger.
291 func Info(msg string, args ...any) {
292         Default().log(context.Background(), LevelInfo, msg, args...)
293 }
294
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...)
298 }
299
300 // Warn calls [Logger.Warn] on the default logger.
301 func Warn(msg string, args ...any) {
302         Default().log(context.Background(), LevelWarn, msg, args...)
303 }
304
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...)
308 }
309
310 // Error calls [Logger.Error] on the default logger.
311 func Error(msg string, args ...any) {
312         Default().log(context.Background(), LevelError, msg, args...)
313 }
314
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...)
318 }
319
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...)
323 }
324
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...)
328 }