Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/go.uber.org/zap/config.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
"errors"
25
"sort"
26
"time"
27
28
"go.uber.org/zap/zapcore"
29
)
30
31
// SamplingConfig sets a sampling strategy for the logger. Sampling caps the
32
// global CPU and I/O load that logging puts on your process while attempting
33
// to preserve a representative subset of your logs.
34
//
35
// If specified, the Sampler will invoke the Hook after each decision.
36
//
37
// Values configured here are per-second. See zapcore.NewSamplerWithOptions for
38
// details.
39
type SamplingConfig struct {
40
Initial int `json:"initial" yaml:"initial"`
41
Thereafter int `json:"thereafter" yaml:"thereafter"`
42
Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
43
}
44
45
// Config offers a declarative way to construct a logger. It doesn't do
46
// anything that can't be done with New, Options, and the various
47
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
48
// toggle common options.
49
//
50
// Note that Config intentionally supports only the most common options. More
51
// unusual logging setups (logging to network connections or message queues,
52
// splitting output between multiple files, etc.) are possible, but require
53
// direct use of the zapcore package. For sample code, see the package-level
54
// BasicConfiguration and AdvancedConfiguration examples.
55
//
56
// For an example showing runtime log level changes, see the documentation for
57
// AtomicLevel.
58
type Config struct {
59
// Level is the minimum enabled logging level. Note that this is a dynamic
60
// level, so calling Config.Level.SetLevel will atomically change the log
61
// level of all loggers descended from this config.
62
Level AtomicLevel `json:"level" yaml:"level"`
63
// Development puts the logger in development mode, which changes the
64
// behavior of DPanicLevel and takes stacktraces more liberally.
65
Development bool `json:"development" yaml:"development"`
66
// DisableCaller stops annotating logs with the calling function's file
67
// name and line number. By default, all logs are annotated.
68
DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
69
// DisableStacktrace completely disables automatic stacktrace capturing. By
70
// default, stacktraces are captured for WarnLevel and above logs in
71
// development and ErrorLevel and above in production.
72
DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
73
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
74
Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
75
// Encoding sets the logger's encoding. Valid values are "json" and
76
// "console", as well as any third-party encodings registered via
77
// RegisterEncoder.
78
Encoding string `json:"encoding" yaml:"encoding"`
79
// EncoderConfig sets options for the chosen encoder. See
80
// zapcore.EncoderConfig for details.
81
EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
82
// OutputPaths is a list of URLs or file paths to write logging output to.
83
// See Open for details.
84
OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
85
// ErrorOutputPaths is a list of URLs to write internal logger errors to.
86
// The default is standard error.
87
//
88
// Note that this setting only affects internal errors; for sample code that
89
// sends error-level logs to a different location from info- and debug-level
90
// logs, see the package-level AdvancedConfiguration example.
91
ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
92
// InitialFields is a collection of fields to add to the root logger.
93
InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
94
}
95
96
// NewProductionEncoderConfig returns an opinionated EncoderConfig for
97
// production environments.
98
//
99
// Messages encoded with this configuration will be JSON-formatted
100
// and will have the following keys by default:
101
//
102
// - "level": The logging level (e.g. "info", "error").
103
// - "ts": The current time in number of seconds since the Unix epoch.
104
// - "msg": The message passed to the log statement.
105
// - "caller": If available, a short path to the file and line number
106
// where the log statement was issued.
107
// The logger configuration determines whether this field is captured.
108
// - "stacktrace": If available, a stack trace from the line
109
// where the log statement was issued.
110
// The logger configuration determines whether this field is captured.
111
//
112
// By default, the following formats are used for different types:
113
//
114
// - Time is formatted as floating-point number of seconds since the Unix
115
// epoch.
116
// - Duration is formatted as floating-point number of seconds.
117
//
118
// You may change these by setting the appropriate fields in the returned
119
// object.
120
// For example, use the following to change the time encoding format:
121
//
122
// cfg := zap.NewProductionEncoderConfig()
123
// cfg.EncodeTime = zapcore.ISO8601TimeEncoder
124
func NewProductionEncoderConfig() zapcore.EncoderConfig {
125
return zapcore.EncoderConfig{
126
TimeKey: "ts",
127
LevelKey: "level",
128
NameKey: "logger",
129
CallerKey: "caller",
130
FunctionKey: zapcore.OmitKey,
131
MessageKey: "msg",
132
StacktraceKey: "stacktrace",
133
LineEnding: zapcore.DefaultLineEnding,
134
EncodeLevel: zapcore.LowercaseLevelEncoder,
135
EncodeTime: zapcore.EpochTimeEncoder,
136
EncodeDuration: zapcore.SecondsDurationEncoder,
137
EncodeCaller: zapcore.ShortCallerEncoder,
138
}
139
}
140
141
// NewProductionConfig builds a reasonable default production logging
142
// configuration.
143
// Logging is enabled at InfoLevel and above, and uses a JSON encoder.
144
// Logs are written to standard error.
145
// Stacktraces are included on logs of ErrorLevel and above.
146
// DPanicLevel logs will not panic, but will write a stacktrace.
147
//
148
// Sampling is enabled at 100:100 by default,
149
// meaning that after the first 100 log entries
150
// with the same level and message in the same second,
151
// it will log every 100th entry
152
// with the same level and message in the same second.
153
// You may disable this behavior by setting Sampling to nil.
154
//
155
// See [NewProductionEncoderConfig] for information
156
// on the default encoder configuration.
157
func NewProductionConfig() Config {
158
return Config{
159
Level: NewAtomicLevelAt(InfoLevel),
160
Development: false,
161
Sampling: &SamplingConfig{
162
Initial: 100,
163
Thereafter: 100,
164
},
165
Encoding: "json",
166
EncoderConfig: NewProductionEncoderConfig(),
167
OutputPaths: []string{"stderr"},
168
ErrorOutputPaths: []string{"stderr"},
169
}
170
}
171
172
// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
173
// development environments.
174
//
175
// Messages encoded with this configuration will use Zap's console encoder
176
// intended to print human-readable output.
177
// It will print log messages with the following information:
178
//
179
// - The log level (e.g. "INFO", "ERROR").
180
// - The time in ISO8601 format (e.g. "2017-01-01T12:00:00Z").
181
// - The message passed to the log statement.
182
// - If available, a short path to the file and line number
183
// where the log statement was issued.
184
// The logger configuration determines whether this field is captured.
185
// - If available, a stacktrace from the line
186
// where the log statement was issued.
187
// The logger configuration determines whether this field is captured.
188
//
189
// By default, the following formats are used for different types:
190
//
191
// - Time is formatted in ISO8601 format (e.g. "2017-01-01T12:00:00Z").
192
// - Duration is formatted as a string (e.g. "1.234s").
193
//
194
// You may change these by setting the appropriate fields in the returned
195
// object.
196
// For example, use the following to change the time encoding format:
197
//
198
// cfg := zap.NewDevelopmentEncoderConfig()
199
// cfg.EncodeTime = zapcore.ISO8601TimeEncoder
200
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
201
return zapcore.EncoderConfig{
202
// Keys can be anything except the empty string.
203
TimeKey: "T",
204
LevelKey: "L",
205
NameKey: "N",
206
CallerKey: "C",
207
FunctionKey: zapcore.OmitKey,
208
MessageKey: "M",
209
StacktraceKey: "S",
210
LineEnding: zapcore.DefaultLineEnding,
211
EncodeLevel: zapcore.CapitalLevelEncoder,
212
EncodeTime: zapcore.ISO8601TimeEncoder,
213
EncodeDuration: zapcore.StringDurationEncoder,
214
EncodeCaller: zapcore.ShortCallerEncoder,
215
}
216
}
217
218
// NewDevelopmentConfig builds a reasonable default development logging
219
// configuration.
220
// Logging is enabled at DebugLevel and above, and uses a console encoder.
221
// Logs are written to standard error.
222
// Stacktraces are included on logs of WarnLevel and above.
223
// DPanicLevel logs will panic.
224
//
225
// See [NewDevelopmentEncoderConfig] for information
226
// on the default encoder configuration.
227
func NewDevelopmentConfig() Config {
228
return Config{
229
Level: NewAtomicLevelAt(DebugLevel),
230
Development: true,
231
Encoding: "console",
232
EncoderConfig: NewDevelopmentEncoderConfig(),
233
OutputPaths: []string{"stderr"},
234
ErrorOutputPaths: []string{"stderr"},
235
}
236
}
237
238
// Build constructs a logger from the Config and Options.
239
func (cfg Config) Build(opts ...Option) (*Logger, error) {
240
enc, err := cfg.buildEncoder()
241
if err != nil {
242
return nil, err
243
}
244
245
sink, errSink, err := cfg.openSinks()
246
if err != nil {
247
return nil, err
248
}
249
250
if cfg.Level == (AtomicLevel{}) {
251
return nil, errors.New("missing Level")
252
}
253
254
log := New(
255
zapcore.NewCore(enc, sink, cfg.Level),
256
cfg.buildOptions(errSink)...,
257
)
258
if len(opts) > 0 {
259
log = log.WithOptions(opts...)
260
}
261
return log, nil
262
}
263
264
func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
265
opts := []Option{ErrorOutput(errSink)}
266
267
if cfg.Development {
268
opts = append(opts, Development())
269
}
270
271
if !cfg.DisableCaller {
272
opts = append(opts, AddCaller())
273
}
274
275
stackLevel := ErrorLevel
276
if cfg.Development {
277
stackLevel = WarnLevel
278
}
279
if !cfg.DisableStacktrace {
280
opts = append(opts, AddStacktrace(stackLevel))
281
}
282
283
if scfg := cfg.Sampling; scfg != nil {
284
opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
285
var samplerOpts []zapcore.SamplerOption
286
if scfg.Hook != nil {
287
samplerOpts = append(samplerOpts, zapcore.SamplerHook(scfg.Hook))
288
}
289
return zapcore.NewSamplerWithOptions(
290
core,
291
time.Second,
292
cfg.Sampling.Initial,
293
cfg.Sampling.Thereafter,
294
samplerOpts...,
295
)
296
}))
297
}
298
299
if len(cfg.InitialFields) > 0 {
300
fs := make([]Field, 0, len(cfg.InitialFields))
301
keys := make([]string, 0, len(cfg.InitialFields))
302
for k := range cfg.InitialFields {
303
keys = append(keys, k)
304
}
305
sort.Strings(keys)
306
for _, k := range keys {
307
fs = append(fs, Any(k, cfg.InitialFields[k]))
308
}
309
opts = append(opts, Fields(fs...))
310
}
311
312
return opts
313
}
314
315
func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
316
sink, closeOut, err := Open(cfg.OutputPaths...)
317
if err != nil {
318
return nil, nil, err
319
}
320
errSink, _, err := Open(cfg.ErrorOutputPaths...)
321
if err != nil {
322
closeOut()
323
return nil, nil, err
324
}
325
return sink, errSink, nil
326
}
327
328
func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
329
return newEncoder(cfg.Encoding, cfg.EncoderConfig)
330
}
331
332