]> Cypherpunks.ru repositories - gostls13.git/blob - src/log/slog/logger.go
c997dd31dc679023a640976464d32e6c9f4ab9ea
[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.Value
18
19 func init() {
20         defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
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         var (
99                 attr  Attr
100                 attrs []Attr
101         )
102         for len(args) > 0 {
103                 attr, args = argsToAttr(args)
104                 attrs = append(attrs, attr)
105         }
106         c := l.clone()
107         c.handler = l.handler.WithAttrs(attrs)
108         return c
109 }
110
111 // WithGroup returns a new Logger that starts a group. The keys of all
112 // attributes added to the Logger will be qualified by the given name.
113 // (How that qualification happens depends on the [Handler.WithGroup]
114 // method of the Logger's Handler.)
115 // The new Logger shares the old Logger's context.
116 //
117 // The new Logger's handler is the result of calling WithGroup on the receiver's
118 // handler.
119 func (l *Logger) WithGroup(name string) *Logger {
120         c := l.clone()
121         c.handler = l.handler.WithGroup(name)
122         return c
123
124 }
125
126 // New creates a new Logger with the given non-nil Handler and a nil context.
127 func New(h Handler) *Logger {
128         if h == nil {
129                 panic("nil Handler")
130         }
131         return &Logger{handler: h}
132 }
133
134 // With calls Logger.With on the default logger.
135 func With(args ...any) *Logger {
136         return Default().With(args...)
137 }
138
139 // Enabled reports whether l emits log records at the given context and level.
140 func (l *Logger) Enabled(ctx context.Context, level Level) bool {
141         if ctx == nil {
142                 ctx = context.Background()
143         }
144         return l.Handler().Enabled(ctx, level)
145 }
146
147 // NewLogLogger returns a new log.Logger such that each call to its Output method
148 // dispatches a Record to the specified handler. The logger acts as a bridge from
149 // the older log API to newer structured logging handlers.
150 func NewLogLogger(h Handler, level Level) *log.Logger {
151         return log.New(&handlerWriter{h, level, true}, "", 0)
152 }
153
154 // Log emits a log record with the current time and the given level and message.
155 // The Record's Attrs consist of the Logger's attributes followed by
156 // the Attrs specified by args.
157 //
158 // The attribute arguments are processed as follows:
159 //   - If an argument is an Attr, it is used as is.
160 //   - If an argument is a string and this is not the last argument,
161 //     the following argument is treated as the value and the two are combined
162 //     into an Attr.
163 //   - Otherwise, the argument is treated as a value with key "!BADKEY".
164 func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any) {
165         l.log(ctx, level, msg, args...)
166 }
167
168 // LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs.
169 func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
170         l.logAttrs(ctx, level, msg, attrs...)
171 }
172
173 // Debug logs at LevelDebug.
174 func (l *Logger) Debug(msg string, args ...any) {
175         l.log(nil, LevelDebug, msg, args...)
176 }
177
178 // DebugCtx logs at LevelDebug with the given context.
179 func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) {
180         l.log(ctx, LevelDebug, msg, args...)
181 }
182
183 // Info logs at LevelInfo.
184 func (l *Logger) Info(msg string, args ...any) {
185         l.log(nil, LevelInfo, msg, args...)
186 }
187
188 // InfoCtx logs at LevelInfo with the given context.
189 func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) {
190         l.log(ctx, LevelInfo, msg, args...)
191 }
192
193 // Warn logs at LevelWarn.
194 func (l *Logger) Warn(msg string, args ...any) {
195         l.log(nil, LevelWarn, msg, args...)
196 }
197
198 // WarnCtx logs at LevelWarn with the given context.
199 func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) {
200         l.log(ctx, LevelWarn, msg, args...)
201 }
202
203 // Error logs at LevelError.
204 func (l *Logger) Error(msg string, args ...any) {
205         l.log(nil, LevelError, msg, args...)
206 }
207
208 // ErrorCtx logs at LevelError with the given context.
209 func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) {
210         l.log(ctx, LevelError, msg, args...)
211 }
212
213 // log is the low-level logging method for methods that take ...any.
214 // It must always be called directly by an exported logging method
215 // or function, because it uses a fixed call depth to obtain the pc.
216 func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) {
217         if !l.Enabled(ctx, level) {
218                 return
219         }
220         var pc uintptr
221         if !internal.IgnorePC {
222                 var pcs [1]uintptr
223                 // skip [runtime.Callers, this function, this function's caller]
224                 runtime.Callers(3, pcs[:])
225                 pc = pcs[0]
226         }
227         r := NewRecord(time.Now(), level, msg, pc)
228         r.Add(args...)
229         if ctx == nil {
230                 ctx = context.Background()
231         }
232         _ = l.Handler().Handle(ctx, r)
233 }
234
235 // logAttrs is like [Logger.log], but for methods that take ...Attr.
236 func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
237         if !l.Enabled(ctx, level) {
238                 return
239         }
240         var pc uintptr
241         if !internal.IgnorePC {
242                 var pcs [1]uintptr
243                 // skip [runtime.Callers, this function, this function's caller]
244                 runtime.Callers(3, pcs[:])
245                 pc = pcs[0]
246         }
247         r := NewRecord(time.Now(), level, msg, pc)
248         r.AddAttrs(attrs...)
249         if ctx == nil {
250                 ctx = context.Background()
251         }
252         _ = l.Handler().Handle(ctx, r)
253 }
254
255 // Debug calls Logger.Debug on the default logger.
256 func Debug(msg string, args ...any) {
257         Default().log(nil, LevelDebug, msg, args...)
258 }
259
260 // DebugCtx calls Logger.DebugCtx on the default logger.
261 func DebugCtx(ctx context.Context, msg string, args ...any) {
262         Default().log(ctx, LevelDebug, msg, args...)
263 }
264
265 // Info calls Logger.Info on the default logger.
266 func Info(msg string, args ...any) {
267         Default().log(nil, LevelInfo, msg, args...)
268 }
269
270 // InfoCtx calls Logger.InfoCtx on the default logger.
271 func InfoCtx(ctx context.Context, msg string, args ...any) {
272         Default().log(ctx, LevelInfo, msg, args...)
273 }
274
275 // Warn calls Logger.Warn on the default logger.
276 func Warn(msg string, args ...any) {
277         Default().log(nil, LevelWarn, msg, args...)
278 }
279
280 // WarnCtx calls Logger.WarnCtx on the default logger.
281 func WarnCtx(ctx context.Context, msg string, args ...any) {
282         Default().log(ctx, LevelWarn, msg, args...)
283 }
284
285 // Error calls Logger.Error on the default logger.
286 func Error(msg string, args ...any) {
287         Default().log(nil, LevelError, msg, args...)
288 }
289
290 // ErrorCtx calls Logger.ErrorCtx on the default logger.
291 func ErrorCtx(ctx context.Context, msg string, args ...any) {
292         Default().log(ctx, LevelError, msg, args...)
293 }
294
295 // Log calls Logger.Log on the default logger.
296 func Log(ctx context.Context, level Level, msg string, args ...any) {
297         Default().log(ctx, level, msg, args...)
298 }
299
300 // LogAttrs calls Logger.LogAttrs on the default logger.
301 func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
302         Default().logAttrs(ctx, level, msg, attrs...)
303 }