1 // Copyright (c) 2016 Uber Technologies, Inc.
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:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
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
27 "go.uber.org/zap/zapcore"
30 // SamplingConfig sets a sampling strategy for the logger. Sampling caps the
31 // global CPU and I/O load that logging puts on your process while attempting
32 // to preserve a representative subset of your logs.
34 // Values configured here are per-second. See zapcore.NewSampler for details.
35 type SamplingConfig struct {
36 Initial int `json:"initial" yaml:"initial"`
37 Thereafter int `json:"thereafter" yaml:"thereafter"`
40 // Config offers a declarative way to construct a logger. It doesn't do
41 // anything that can't be done with New, Options, and the various
42 // zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
43 // toggle common options.
45 // Note that Config intentionally supports only the most common options. More
46 // unusual logging setups (logging to network connections or message queues,
47 // splitting output between multiple files, etc.) are possible, but require
48 // direct use of the zapcore package. For sample code, see the package-level
49 // BasicConfiguration and AdvancedConfiguration examples.
51 // For an example showing runtime log level changes, see the documentation for
54 // Level is the minimum enabled logging level. Note that this is a dynamic
55 // level, so calling Config.Level.SetLevel will atomically change the log
56 // level of all loggers descended from this config.
57 Level AtomicLevel `json:"level" yaml:"level"`
58 // Development puts the logger in development mode, which changes the
59 // behavior of DPanicLevel and takes stacktraces more liberally.
60 Development bool `json:"development" yaml:"development"`
61 // DisableCaller stops annotating logs with the calling function's file
62 // name and line number. By default, all logs are annotated.
63 DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
64 // DisableStacktrace completely disables automatic stacktrace capturing. By
65 // default, stacktraces are captured for WarnLevel and above logs in
66 // development and ErrorLevel and above in production.
67 DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
68 // Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
69 Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
70 // Encoding sets the logger's encoding. Valid values are "json" and
71 // "console", as well as any third-party encodings registered via
73 Encoding string `json:"encoding" yaml:"encoding"`
74 // EncoderConfig sets options for the chosen encoder. See
75 // zapcore.EncoderConfig for details.
76 EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
77 // OutputPaths is a list of URLs or file paths to write logging output to.
78 // See Open for details.
79 OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
80 // ErrorOutputPaths is a list of URLs to write internal logger errors to.
81 // The default is standard error.
83 // Note that this setting only affects internal errors; for sample code that
84 // sends error-level logs to a different location from info- and debug-level
85 // logs, see the package-level AdvancedConfiguration example.
86 ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
87 // InitialFields is a collection of fields to add to the root logger.
88 InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
91 // NewProductionEncoderConfig returns an opinionated EncoderConfig for
92 // production environments.
93 func NewProductionEncoderConfig() zapcore.EncoderConfig {
94 return zapcore.EncoderConfig{
100 StacktraceKey: "stacktrace",
101 LineEnding: zapcore.DefaultLineEnding,
102 EncodeLevel: zapcore.LowercaseLevelEncoder,
103 EncodeTime: zapcore.EpochTimeEncoder,
104 EncodeDuration: zapcore.SecondsDurationEncoder,
105 EncodeCaller: zapcore.ShortCallerEncoder,
109 // NewProductionConfig is a reasonable production logging configuration.
110 // Logging is enabled at InfoLevel and above.
112 // It uses a JSON encoder, writes to standard error, and enables sampling.
113 // Stacktraces are automatically included on logs of ErrorLevel and above.
114 func NewProductionConfig() Config {
116 Level: NewAtomicLevelAt(InfoLevel),
118 Sampling: &SamplingConfig{
123 EncoderConfig: NewProductionEncoderConfig(),
124 OutputPaths: []string{"stderr"},
125 ErrorOutputPaths: []string{"stderr"},
129 // NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for
130 // development environments.
131 func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
132 return zapcore.EncoderConfig{
133 // Keys can be anything except the empty string.
140 LineEnding: zapcore.DefaultLineEnding,
141 EncodeLevel: zapcore.CapitalLevelEncoder,
142 EncodeTime: zapcore.ISO8601TimeEncoder,
143 EncodeDuration: zapcore.StringDurationEncoder,
144 EncodeCaller: zapcore.ShortCallerEncoder,
148 // NewDevelopmentConfig is a reasonable development logging configuration.
149 // Logging is enabled at DebugLevel and above.
151 // It enables development mode (which makes DPanicLevel logs panic), uses a
152 // console encoder, writes to standard error, and disables sampling.
153 // Stacktraces are automatically included on logs of WarnLevel and above.
154 func NewDevelopmentConfig() Config {
156 Level: NewAtomicLevelAt(DebugLevel),
159 EncoderConfig: NewDevelopmentEncoderConfig(),
160 OutputPaths: []string{"stderr"},
161 ErrorOutputPaths: []string{"stderr"},
165 // Build constructs a logger from the Config and Options.
166 func (cfg Config) Build(opts ...Option) (*Logger, error) {
167 enc, err := cfg.buildEncoder()
172 sink, errSink, err := cfg.openSinks()
178 zapcore.NewCore(enc, sink, cfg.Level),
179 cfg.buildOptions(errSink)...,
182 log = log.WithOptions(opts...)
187 func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
188 opts := []Option{ErrorOutput(errSink)}
191 opts = append(opts, Development())
194 if !cfg.DisableCaller {
195 opts = append(opts, AddCaller())
198 stackLevel := ErrorLevel
200 stackLevel = WarnLevel
202 if !cfg.DisableStacktrace {
203 opts = append(opts, AddStacktrace(stackLevel))
206 if cfg.Sampling != nil {
207 opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core {
208 return zapcore.NewSampler(core, time.Second, int(cfg.Sampling.Initial), int(cfg.Sampling.Thereafter))
212 if len(cfg.InitialFields) > 0 {
213 fs := make([]Field, 0, len(cfg.InitialFields))
214 keys := make([]string, 0, len(cfg.InitialFields))
215 for k := range cfg.InitialFields {
216 keys = append(keys, k)
219 for _, k := range keys {
220 fs = append(fs, Any(k, cfg.InitialFields[k]))
222 opts = append(opts, Fields(fs...))
228 func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
229 sink, closeOut, err := Open(cfg.OutputPaths...)
233 errSink, _, err := Open(cfg.ErrorOutputPaths...)
238 return sink, errSink, nil
241 func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
242 return newEncoder(cfg.Encoding, cfg.EncoderConfig)