Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / go.uber.org / zap / config.go
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         "sort"
25         "time"
26
27         "go.uber.org/zap/zapcore"
28 )
29
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.
33 //
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"`
38 }
39
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.
44 //
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.
50 //
51 // For an example showing runtime log level changes, see the documentation for
52 // AtomicLevel.
53 type Config struct {
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
72         // RegisterEncoder.
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.
82         //
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"`
89 }
90
91 // NewProductionEncoderConfig returns an opinionated EncoderConfig for
92 // production environments.
93 func NewProductionEncoderConfig() zapcore.EncoderConfig {
94         return zapcore.EncoderConfig{
95                 TimeKey:        "ts",
96                 LevelKey:       "level",
97                 NameKey:        "logger",
98                 CallerKey:      "caller",
99                 MessageKey:     "msg",
100                 StacktraceKey:  "stacktrace",
101                 LineEnding:     zapcore.DefaultLineEnding,
102                 EncodeLevel:    zapcore.LowercaseLevelEncoder,
103                 EncodeTime:     zapcore.EpochTimeEncoder,
104                 EncodeDuration: zapcore.SecondsDurationEncoder,
105                 EncodeCaller:   zapcore.ShortCallerEncoder,
106         }
107 }
108
109 // NewProductionConfig is a reasonable production logging configuration.
110 // Logging is enabled at InfoLevel and above.
111 //
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 {
115         return Config{
116                 Level:       NewAtomicLevelAt(InfoLevel),
117                 Development: false,
118                 Sampling: &SamplingConfig{
119                         Initial:    100,
120                         Thereafter: 100,
121                 },
122                 Encoding:         "json",
123                 EncoderConfig:    NewProductionEncoderConfig(),
124                 OutputPaths:      []string{"stderr"},
125                 ErrorOutputPaths: []string{"stderr"},
126         }
127 }
128
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.
134                 TimeKey:        "T",
135                 LevelKey:       "L",
136                 NameKey:        "N",
137                 CallerKey:      "C",
138                 MessageKey:     "M",
139                 StacktraceKey:  "S",
140                 LineEnding:     zapcore.DefaultLineEnding,
141                 EncodeLevel:    zapcore.CapitalLevelEncoder,
142                 EncodeTime:     zapcore.ISO8601TimeEncoder,
143                 EncodeDuration: zapcore.StringDurationEncoder,
144                 EncodeCaller:   zapcore.ShortCallerEncoder,
145         }
146 }
147
148 // NewDevelopmentConfig is a reasonable development logging configuration.
149 // Logging is enabled at DebugLevel and above.
150 //
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 {
155         return Config{
156                 Level:            NewAtomicLevelAt(DebugLevel),
157                 Development:      true,
158                 Encoding:         "console",
159                 EncoderConfig:    NewDevelopmentEncoderConfig(),
160                 OutputPaths:      []string{"stderr"},
161                 ErrorOutputPaths: []string{"stderr"},
162         }
163 }
164
165 // Build constructs a logger from the Config and Options.
166 func (cfg Config) Build(opts ...Option) (*Logger, error) {
167         enc, err := cfg.buildEncoder()
168         if err != nil {
169                 return nil, err
170         }
171
172         sink, errSink, err := cfg.openSinks()
173         if err != nil {
174                 return nil, err
175         }
176
177         log := New(
178                 zapcore.NewCore(enc, sink, cfg.Level),
179                 cfg.buildOptions(errSink)...,
180         )
181         if len(opts) > 0 {
182                 log = log.WithOptions(opts...)
183         }
184         return log, nil
185 }
186
187 func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option {
188         opts := []Option{ErrorOutput(errSink)}
189
190         if cfg.Development {
191                 opts = append(opts, Development())
192         }
193
194         if !cfg.DisableCaller {
195                 opts = append(opts, AddCaller())
196         }
197
198         stackLevel := ErrorLevel
199         if cfg.Development {
200                 stackLevel = WarnLevel
201         }
202         if !cfg.DisableStacktrace {
203                 opts = append(opts, AddStacktrace(stackLevel))
204         }
205
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))
209                 }))
210         }
211
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)
217                 }
218                 sort.Strings(keys)
219                 for _, k := range keys {
220                         fs = append(fs, Any(k, cfg.InitialFields[k]))
221                 }
222                 opts = append(opts, Fields(fs...))
223         }
224
225         return opts
226 }
227
228 func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) {
229         sink, closeOut, err := Open(cfg.OutputPaths...)
230         if err != nil {
231                 return nil, nil, err
232         }
233         errSink, _, err := Open(cfg.ErrorOutputPaths...)
234         if err != nil {
235                 closeOut()
236                 return nil, nil, err
237         }
238         return sink, errSink, nil
239 }
240
241 func (cfg Config) buildEncoder() (zapcore.Encoder, error) {
242         return newEncoder(cfg.Encoding, cfg.EncoderConfig)
243 }