Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/go.uber.org/zap/sugar.go
2872 views
1
// Copyright (c) 2016 Uber Technologies, Inc.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a copy
4
// of this software and associated documentation files (the "Software"), to deal
5
// in the Software without restriction, including without limitation the rights
6
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
// copies of the Software, and to permit persons to whom the Software is
8
// furnished to do so, subject to the following conditions:
9
//
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
12
//
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
// THE SOFTWARE.
20
21
package zap
22
23
import (
24
"fmt"
25
26
"go.uber.org/zap/zapcore"
27
28
"go.uber.org/multierr"
29
)
30
31
const (
32
_oddNumberErrMsg = "Ignored key without a value."
33
_nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys."
34
_multipleErrMsg = "Multiple errors without a key."
35
)
36
37
// A SugaredLogger wraps the base Logger functionality in a slower, but less
38
// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar
39
// method.
40
//
41
// Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
42
// For each log level, it exposes four methods:
43
//
44
// - methods named after the log level for log.Print-style logging
45
// - methods ending in "w" for loosely-typed structured logging
46
// - methods ending in "f" for log.Printf-style logging
47
// - methods ending in "ln" for log.Println-style logging
48
//
49
// For example, the methods for InfoLevel are:
50
//
51
// Info(...any) Print-style logging
52
// Infow(...any) Structured logging (read as "info with")
53
// Infof(string, ...any) Printf-style logging
54
// Infoln(...any) Println-style logging
55
type SugaredLogger struct {
56
base *Logger
57
}
58
59
// Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring
60
// is quite inexpensive, so it's reasonable for a single application to use
61
// both Loggers and SugaredLoggers, converting between them on the boundaries
62
// of performance-sensitive code.
63
func (s *SugaredLogger) Desugar() *Logger {
64
base := s.base.clone()
65
base.callerSkip -= 2
66
return base
67
}
68
69
// Named adds a sub-scope to the logger's name. See Logger.Named for details.
70
func (s *SugaredLogger) Named(name string) *SugaredLogger {
71
return &SugaredLogger{base: s.base.Named(name)}
72
}
73
74
// WithOptions clones the current SugaredLogger, applies the supplied Options,
75
// and returns the result. It's safe to use concurrently.
76
func (s *SugaredLogger) WithOptions(opts ...Option) *SugaredLogger {
77
base := s.base.clone()
78
for _, opt := range opts {
79
opt.apply(base)
80
}
81
return &SugaredLogger{base: base}
82
}
83
84
// With adds a variadic number of fields to the logging context. It accepts a
85
// mix of strongly-typed Field objects and loosely-typed key-value pairs. When
86
// processing pairs, the first element of the pair is used as the field key
87
// and the second as the field value.
88
//
89
// For example,
90
//
91
// sugaredLogger.With(
92
// "hello", "world",
93
// "failure", errors.New("oh no"),
94
// Stack(),
95
// "count", 42,
96
// "user", User{Name: "alice"},
97
// )
98
//
99
// is the equivalent of
100
//
101
// unsugared.With(
102
// String("hello", "world"),
103
// String("failure", "oh no"),
104
// Stack(),
105
// Int("count", 42),
106
// Object("user", User{Name: "alice"}),
107
// )
108
//
109
// Note that the keys in key-value pairs should be strings. In development,
110
// passing a non-string key panics. In production, the logger is more
111
// forgiving: a separate error is logged, but the key-value pair is skipped
112
// and execution continues. Passing an orphaned key triggers similar behavior:
113
// panics in development and errors in production.
114
func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger {
115
return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)}
116
}
117
118
// WithLazy adds a variadic number of fields to the logging context lazily.
119
// The fields are evaluated only if the logger is further chained with [With]
120
// or is written to with any of the log level methods.
121
// Until that occurs, the logger may retain references to objects inside the fields,
122
// and logging will reflect the state of an object at the time of logging,
123
// not the time of WithLazy().
124
//
125
// Similar to [With], fields added to the child don't affect the parent,
126
// and vice versa. Also, the keys in key-value pairs should be strings. In development,
127
// passing a non-string key panics, while in production it logs an error and skips the pair.
128
// Passing an orphaned key has the same behavior.
129
func (s *SugaredLogger) WithLazy(args ...interface{}) *SugaredLogger {
130
return &SugaredLogger{base: s.base.WithLazy(s.sweetenFields(args)...)}
131
}
132
133
// Level reports the minimum enabled level for this logger.
134
//
135
// For NopLoggers, this is [zapcore.InvalidLevel].
136
func (s *SugaredLogger) Level() zapcore.Level {
137
return zapcore.LevelOf(s.base.core)
138
}
139
140
// Log logs the provided arguments at provided level.
141
// Spaces are added between arguments when neither is a string.
142
func (s *SugaredLogger) Log(lvl zapcore.Level, args ...interface{}) {
143
s.log(lvl, "", args, nil)
144
}
145
146
// Debug logs the provided arguments at [DebugLevel].
147
// Spaces are added between arguments when neither is a string.
148
func (s *SugaredLogger) Debug(args ...interface{}) {
149
s.log(DebugLevel, "", args, nil)
150
}
151
152
// Info logs the provided arguments at [InfoLevel].
153
// Spaces are added between arguments when neither is a string.
154
func (s *SugaredLogger) Info(args ...interface{}) {
155
s.log(InfoLevel, "", args, nil)
156
}
157
158
// Warn logs the provided arguments at [WarnLevel].
159
// Spaces are added between arguments when neither is a string.
160
func (s *SugaredLogger) Warn(args ...interface{}) {
161
s.log(WarnLevel, "", args, nil)
162
}
163
164
// Error logs the provided arguments at [ErrorLevel].
165
// Spaces are added between arguments when neither is a string.
166
func (s *SugaredLogger) Error(args ...interface{}) {
167
s.log(ErrorLevel, "", args, nil)
168
}
169
170
// DPanic logs the provided arguments at [DPanicLevel].
171
// In development, the logger then panics. (See [DPanicLevel] for details.)
172
// Spaces are added between arguments when neither is a string.
173
func (s *SugaredLogger) DPanic(args ...interface{}) {
174
s.log(DPanicLevel, "", args, nil)
175
}
176
177
// Panic constructs a message with the provided arguments and panics.
178
// Spaces are added between arguments when neither is a string.
179
func (s *SugaredLogger) Panic(args ...interface{}) {
180
s.log(PanicLevel, "", args, nil)
181
}
182
183
// Fatal constructs a message with the provided arguments and calls os.Exit.
184
// Spaces are added between arguments when neither is a string.
185
func (s *SugaredLogger) Fatal(args ...interface{}) {
186
s.log(FatalLevel, "", args, nil)
187
}
188
189
// Logf formats the message according to the format specifier
190
// and logs it at provided level.
191
func (s *SugaredLogger) Logf(lvl zapcore.Level, template string, args ...interface{}) {
192
s.log(lvl, template, args, nil)
193
}
194
195
// Debugf formats the message according to the format specifier
196
// and logs it at [DebugLevel].
197
func (s *SugaredLogger) Debugf(template string, args ...interface{}) {
198
s.log(DebugLevel, template, args, nil)
199
}
200
201
// Infof formats the message according to the format specifier
202
// and logs it at [InfoLevel].
203
func (s *SugaredLogger) Infof(template string, args ...interface{}) {
204
s.log(InfoLevel, template, args, nil)
205
}
206
207
// Warnf formats the message according to the format specifier
208
// and logs it at [WarnLevel].
209
func (s *SugaredLogger) Warnf(template string, args ...interface{}) {
210
s.log(WarnLevel, template, args, nil)
211
}
212
213
// Errorf formats the message according to the format specifier
214
// and logs it at [ErrorLevel].
215
func (s *SugaredLogger) Errorf(template string, args ...interface{}) {
216
s.log(ErrorLevel, template, args, nil)
217
}
218
219
// DPanicf formats the message according to the format specifier
220
// and logs it at [DPanicLevel].
221
// In development, the logger then panics. (See [DPanicLevel] for details.)
222
func (s *SugaredLogger) DPanicf(template string, args ...interface{}) {
223
s.log(DPanicLevel, template, args, nil)
224
}
225
226
// Panicf formats the message according to the format specifier
227
// and panics.
228
func (s *SugaredLogger) Panicf(template string, args ...interface{}) {
229
s.log(PanicLevel, template, args, nil)
230
}
231
232
// Fatalf formats the message according to the format specifier
233
// and calls os.Exit.
234
func (s *SugaredLogger) Fatalf(template string, args ...interface{}) {
235
s.log(FatalLevel, template, args, nil)
236
}
237
238
// Logw logs a message with some additional context. The variadic key-value
239
// pairs are treated as they are in With.
240
func (s *SugaredLogger) Logw(lvl zapcore.Level, msg string, keysAndValues ...interface{}) {
241
s.log(lvl, msg, nil, keysAndValues)
242
}
243
244
// Debugw logs a message with some additional context. The variadic key-value
245
// pairs are treated as they are in With.
246
//
247
// When debug-level logging is disabled, this is much faster than
248
//
249
// s.With(keysAndValues).Debug(msg)
250
func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) {
251
s.log(DebugLevel, msg, nil, keysAndValues)
252
}
253
254
// Infow logs a message with some additional context. The variadic key-value
255
// pairs are treated as they are in With.
256
func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) {
257
s.log(InfoLevel, msg, nil, keysAndValues)
258
}
259
260
// Warnw logs a message with some additional context. The variadic key-value
261
// pairs are treated as they are in With.
262
func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) {
263
s.log(WarnLevel, msg, nil, keysAndValues)
264
}
265
266
// Errorw logs a message with some additional context. The variadic key-value
267
// pairs are treated as they are in With.
268
func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) {
269
s.log(ErrorLevel, msg, nil, keysAndValues)
270
}
271
272
// DPanicw logs a message with some additional context. In development, the
273
// logger then panics. (See DPanicLevel for details.) The variadic key-value
274
// pairs are treated as they are in With.
275
func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) {
276
s.log(DPanicLevel, msg, nil, keysAndValues)
277
}
278
279
// Panicw logs a message with some additional context, then panics. The
280
// variadic key-value pairs are treated as they are in With.
281
func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) {
282
s.log(PanicLevel, msg, nil, keysAndValues)
283
}
284
285
// Fatalw logs a message with some additional context, then calls os.Exit. The
286
// variadic key-value pairs are treated as they are in With.
287
func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) {
288
s.log(FatalLevel, msg, nil, keysAndValues)
289
}
290
291
// Logln logs a message at provided level.
292
// Spaces are always added between arguments.
293
func (s *SugaredLogger) Logln(lvl zapcore.Level, args ...interface{}) {
294
s.logln(lvl, args, nil)
295
}
296
297
// Debugln logs a message at [DebugLevel].
298
// Spaces are always added between arguments.
299
func (s *SugaredLogger) Debugln(args ...interface{}) {
300
s.logln(DebugLevel, args, nil)
301
}
302
303
// Infoln logs a message at [InfoLevel].
304
// Spaces are always added between arguments.
305
func (s *SugaredLogger) Infoln(args ...interface{}) {
306
s.logln(InfoLevel, args, nil)
307
}
308
309
// Warnln logs a message at [WarnLevel].
310
// Spaces are always added between arguments.
311
func (s *SugaredLogger) Warnln(args ...interface{}) {
312
s.logln(WarnLevel, args, nil)
313
}
314
315
// Errorln logs a message at [ErrorLevel].
316
// Spaces are always added between arguments.
317
func (s *SugaredLogger) Errorln(args ...interface{}) {
318
s.logln(ErrorLevel, args, nil)
319
}
320
321
// DPanicln logs a message at [DPanicLevel].
322
// In development, the logger then panics. (See [DPanicLevel] for details.)
323
// Spaces are always added between arguments.
324
func (s *SugaredLogger) DPanicln(args ...interface{}) {
325
s.logln(DPanicLevel, args, nil)
326
}
327
328
// Panicln logs a message at [PanicLevel] and panics.
329
// Spaces are always added between arguments.
330
func (s *SugaredLogger) Panicln(args ...interface{}) {
331
s.logln(PanicLevel, args, nil)
332
}
333
334
// Fatalln logs a message at [FatalLevel] and calls os.Exit.
335
// Spaces are always added between arguments.
336
func (s *SugaredLogger) Fatalln(args ...interface{}) {
337
s.logln(FatalLevel, args, nil)
338
}
339
340
// Sync flushes any buffered log entries.
341
func (s *SugaredLogger) Sync() error {
342
return s.base.Sync()
343
}
344
345
// log message with Sprint, Sprintf, or neither.
346
func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
347
// If logging at this level is completely disabled, skip the overhead of
348
// string formatting.
349
if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
350
return
351
}
352
353
msg := getMessage(template, fmtArgs)
354
if ce := s.base.Check(lvl, msg); ce != nil {
355
ce.Write(s.sweetenFields(context)...)
356
}
357
}
358
359
// logln message with Sprintln
360
func (s *SugaredLogger) logln(lvl zapcore.Level, fmtArgs []interface{}, context []interface{}) {
361
if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
362
return
363
}
364
365
msg := getMessageln(fmtArgs)
366
if ce := s.base.Check(lvl, msg); ce != nil {
367
ce.Write(s.sweetenFields(context)...)
368
}
369
}
370
371
// getMessage format with Sprint, Sprintf, or neither.
372
func getMessage(template string, fmtArgs []interface{}) string {
373
if len(fmtArgs) == 0 {
374
return template
375
}
376
377
if template != "" {
378
return fmt.Sprintf(template, fmtArgs...)
379
}
380
381
if len(fmtArgs) == 1 {
382
if str, ok := fmtArgs[0].(string); ok {
383
return str
384
}
385
}
386
return fmt.Sprint(fmtArgs...)
387
}
388
389
// getMessageln format with Sprintln.
390
func getMessageln(fmtArgs []interface{}) string {
391
msg := fmt.Sprintln(fmtArgs...)
392
return msg[:len(msg)-1]
393
}
394
395
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
396
if len(args) == 0 {
397
return nil
398
}
399
400
var (
401
// Allocate enough space for the worst case; if users pass only structured
402
// fields, we shouldn't penalize them with extra allocations.
403
fields = make([]Field, 0, len(args))
404
invalid invalidPairs
405
seenError bool
406
)
407
408
for i := 0; i < len(args); {
409
// This is a strongly-typed field. Consume it and move on.
410
if f, ok := args[i].(Field); ok {
411
fields = append(fields, f)
412
i++
413
continue
414
}
415
416
// If it is an error, consume it and move on.
417
if err, ok := args[i].(error); ok {
418
if !seenError {
419
seenError = true
420
fields = append(fields, Error(err))
421
} else {
422
s.base.Error(_multipleErrMsg, Error(err))
423
}
424
i++
425
continue
426
}
427
428
// Make sure this element isn't a dangling key.
429
if i == len(args)-1 {
430
s.base.Error(_oddNumberErrMsg, Any("ignored", args[i]))
431
break
432
}
433
434
// Consume this value and the next, treating them as a key-value pair. If the
435
// key isn't a string, add this pair to the slice of invalid pairs.
436
key, val := args[i], args[i+1]
437
if keyStr, ok := key.(string); !ok {
438
// Subsequent errors are likely, so allocate once up front.
439
if cap(invalid) == 0 {
440
invalid = make(invalidPairs, 0, len(args)/2)
441
}
442
invalid = append(invalid, invalidPair{i, key, val})
443
} else {
444
fields = append(fields, Any(keyStr, val))
445
}
446
i += 2
447
}
448
449
// If we encountered any invalid key-value pairs, log an error.
450
if len(invalid) > 0 {
451
s.base.Error(_nonStringKeyErrMsg, Array("invalid", invalid))
452
}
453
return fields
454
}
455
456
type invalidPair struct {
457
position int
458
key, value interface{}
459
}
460
461
func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error {
462
enc.AddInt64("position", int64(p.position))
463
Any("key", p.key).AddTo(enc)
464
Any("value", p.value).AddTo(enc)
465
return nil
466
}
467
468
type invalidPairs []invalidPair
469
470
func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error {
471
var err error
472
for i := range ps {
473
err = multierr.Append(err, enc.AppendObject(ps[i]))
474
}
475
return err
476
}
477
478