Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / go.uber.org / zap / sugar.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         "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 )
35
36 // A SugaredLogger wraps the base Logger functionality in a slower, but less
37 // verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar
38 // method.
39 //
40 // Unlike the Logger, the SugaredLogger doesn't insist on structured logging.
41 // For each log level, it exposes three methods: one for loosely-typed
42 // structured logging, one for println-style formatting, and one for
43 // printf-style formatting. For example, SugaredLoggers can produce InfoLevel
44 // output with Infow ("info with" structured context), Info, or Infof.
45 type SugaredLogger struct {
46         base *Logger
47 }
48
49 // Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring
50 // is quite inexpensive, so it's reasonable for a single application to use
51 // both Loggers and SugaredLoggers, converting between them on the boundaries
52 // of performance-sensitive code.
53 func (s *SugaredLogger) Desugar() *Logger {
54         base := s.base.clone()
55         base.callerSkip -= 2
56         return base
57 }
58
59 // Named adds a sub-scope to the logger's name. See Logger.Named for details.
60 func (s *SugaredLogger) Named(name string) *SugaredLogger {
61         return &SugaredLogger{base: s.base.Named(name)}
62 }
63
64 // With adds a variadic number of fields to the logging context. It accepts a
65 // mix of strongly-typed Field objects and loosely-typed key-value pairs. When
66 // processing pairs, the first element of the pair is used as the field key
67 // and the second as the field value.
68 //
69 // For example,
70 //   sugaredLogger.With(
71 //     "hello", "world",
72 //     "failure", errors.New("oh no"),
73 //     Stack(),
74 //     "count", 42,
75 //     "user", User{Name: "alice"},
76 //  )
77 // is the equivalent of
78 //   unsugared.With(
79 //     String("hello", "world"),
80 //     String("failure", "oh no"),
81 //     Stack(),
82 //     Int("count", 42),
83 //     Object("user", User{Name: "alice"}),
84 //   )
85 //
86 // Note that the keys in key-value pairs should be strings. In development,
87 // passing a non-string key panics. In production, the logger is more
88 // forgiving: a separate error is logged, but the key-value pair is skipped
89 // and execution continues. Passing an orphaned key triggers similar behavior:
90 // panics in development and errors in production.
91 func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger {
92         return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)}
93 }
94
95 // Debug uses fmt.Sprint to construct and log a message.
96 func (s *SugaredLogger) Debug(args ...interface{}) {
97         s.log(DebugLevel, "", args, nil)
98 }
99
100 // Info uses fmt.Sprint to construct and log a message.
101 func (s *SugaredLogger) Info(args ...interface{}) {
102         s.log(InfoLevel, "", args, nil)
103 }
104
105 // Warn uses fmt.Sprint to construct and log a message.
106 func (s *SugaredLogger) Warn(args ...interface{}) {
107         s.log(WarnLevel, "", args, nil)
108 }
109
110 // Error uses fmt.Sprint to construct and log a message.
111 func (s *SugaredLogger) Error(args ...interface{}) {
112         s.log(ErrorLevel, "", args, nil)
113 }
114
115 // DPanic uses fmt.Sprint to construct and log a message. In development, the
116 // logger then panics. (See DPanicLevel for details.)
117 func (s *SugaredLogger) DPanic(args ...interface{}) {
118         s.log(DPanicLevel, "", args, nil)
119 }
120
121 // Panic uses fmt.Sprint to construct and log a message, then panics.
122 func (s *SugaredLogger) Panic(args ...interface{}) {
123         s.log(PanicLevel, "", args, nil)
124 }
125
126 // Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit.
127 func (s *SugaredLogger) Fatal(args ...interface{}) {
128         s.log(FatalLevel, "", args, nil)
129 }
130
131 // Debugf uses fmt.Sprintf to log a templated message.
132 func (s *SugaredLogger) Debugf(template string, args ...interface{}) {
133         s.log(DebugLevel, template, args, nil)
134 }
135
136 // Infof uses fmt.Sprintf to log a templated message.
137 func (s *SugaredLogger) Infof(template string, args ...interface{}) {
138         s.log(InfoLevel, template, args, nil)
139 }
140
141 // Warnf uses fmt.Sprintf to log a templated message.
142 func (s *SugaredLogger) Warnf(template string, args ...interface{}) {
143         s.log(WarnLevel, template, args, nil)
144 }
145
146 // Errorf uses fmt.Sprintf to log a templated message.
147 func (s *SugaredLogger) Errorf(template string, args ...interface{}) {
148         s.log(ErrorLevel, template, args, nil)
149 }
150
151 // DPanicf uses fmt.Sprintf to log a templated message. In development, the
152 // logger then panics. (See DPanicLevel for details.)
153 func (s *SugaredLogger) DPanicf(template string, args ...interface{}) {
154         s.log(DPanicLevel, template, args, nil)
155 }
156
157 // Panicf uses fmt.Sprintf to log a templated message, then panics.
158 func (s *SugaredLogger) Panicf(template string, args ...interface{}) {
159         s.log(PanicLevel, template, args, nil)
160 }
161
162 // Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit.
163 func (s *SugaredLogger) Fatalf(template string, args ...interface{}) {
164         s.log(FatalLevel, template, args, nil)
165 }
166
167 // Debugw logs a message with some additional context. The variadic key-value
168 // pairs are treated as they are in With.
169 //
170 // When debug-level logging is disabled, this is much faster than
171 //  s.With(keysAndValues).Debug(msg)
172 func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) {
173         s.log(DebugLevel, msg, nil, keysAndValues)
174 }
175
176 // Infow logs a message with some additional context. The variadic key-value
177 // pairs are treated as they are in With.
178 func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) {
179         s.log(InfoLevel, msg, nil, keysAndValues)
180 }
181
182 // Warnw logs a message with some additional context. The variadic key-value
183 // pairs are treated as they are in With.
184 func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) {
185         s.log(WarnLevel, msg, nil, keysAndValues)
186 }
187
188 // Errorw logs a message with some additional context. The variadic key-value
189 // pairs are treated as they are in With.
190 func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) {
191         s.log(ErrorLevel, msg, nil, keysAndValues)
192 }
193
194 // DPanicw logs a message with some additional context. In development, the
195 // logger then panics. (See DPanicLevel for details.) The variadic key-value
196 // pairs are treated as they are in With.
197 func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) {
198         s.log(DPanicLevel, msg, nil, keysAndValues)
199 }
200
201 // Panicw logs a message with some additional context, then panics. The
202 // variadic key-value pairs are treated as they are in With.
203 func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) {
204         s.log(PanicLevel, msg, nil, keysAndValues)
205 }
206
207 // Fatalw logs a message with some additional context, then calls os.Exit. The
208 // variadic key-value pairs are treated as they are in With.
209 func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) {
210         s.log(FatalLevel, msg, nil, keysAndValues)
211 }
212
213 // Sync flushes any buffered log entries.
214 func (s *SugaredLogger) Sync() error {
215         return s.base.Sync()
216 }
217
218 func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) {
219         // If logging at this level is completely disabled, skip the overhead of
220         // string formatting.
221         if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) {
222                 return
223         }
224
225         // Format with Sprint, Sprintf, or neither.
226         msg := template
227         if msg == "" && len(fmtArgs) > 0 {
228                 msg = fmt.Sprint(fmtArgs...)
229         } else if msg != "" && len(fmtArgs) > 0 {
230                 msg = fmt.Sprintf(template, fmtArgs...)
231         }
232
233         if ce := s.base.Check(lvl, msg); ce != nil {
234                 ce.Write(s.sweetenFields(context)...)
235         }
236 }
237
238 func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
239         if len(args) == 0 {
240                 return nil
241         }
242
243         // Allocate enough space for the worst case; if users pass only structured
244         // fields, we shouldn't penalize them with extra allocations.
245         fields := make([]Field, 0, len(args))
246         var invalid invalidPairs
247
248         for i := 0; i < len(args); {
249                 // This is a strongly-typed field. Consume it and move on.
250                 if f, ok := args[i].(Field); ok {
251                         fields = append(fields, f)
252                         i++
253                         continue
254                 }
255
256                 // Make sure this element isn't a dangling key.
257                 if i == len(args)-1 {
258                         s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i]))
259                         break
260                 }
261
262                 // Consume this value and the next, treating them as a key-value pair. If the
263                 // key isn't a string, add this pair to the slice of invalid pairs.
264                 key, val := args[i], args[i+1]
265                 if keyStr, ok := key.(string); !ok {
266                         // Subsequent errors are likely, so allocate once up front.
267                         if cap(invalid) == 0 {
268                                 invalid = make(invalidPairs, 0, len(args)/2)
269                         }
270                         invalid = append(invalid, invalidPair{i, key, val})
271                 } else {
272                         fields = append(fields, Any(keyStr, val))
273                 }
274                 i += 2
275         }
276
277         // If we encountered any invalid key-value pairs, log an error.
278         if len(invalid) > 0 {
279                 s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))
280         }
281         return fields
282 }
283
284 type invalidPair struct {
285         position   int
286         key, value interface{}
287 }
288
289 func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error {
290         enc.AddInt64("position", int64(p.position))
291         Any("key", p.key).AddTo(enc)
292         Any("value", p.value).AddTo(enc)
293         return nil
294 }
295
296 type invalidPairs []invalidPair
297
298 func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error {
299         var err error
300         for i := range ps {
301                 err = multierr.Append(err, enc.AppendObject(ps[i]))
302         }
303         return err
304 }