blob: e9f3c1b5dd54cd77485b4efa02408d4947111a3a [file] [log] [blame]
khenaidoocfee5f42018-07-19 22:47:38 -04001package log
2
3import (
4 "errors"
khenaidoo5c11af72018-07-20 17:21:05 -04005 "fmt"
khenaidoocfee5f42018-07-19 22:47:38 -04006 zp "go.uber.org/zap"
7 zc "go.uber.org/zap/zapcore"
8 "runtime"
9 "strings"
khenaidoocfee5f42018-07-19 22:47:38 -040010)
11
12const (
13 // DebugLevel logs a message at debug level
14 DebugLevel = iota
15 // InfoLevel logs a message at info level
16 InfoLevel
17 // WarnLevel logs a message at warning level
18 WarnLevel
19 // ErrorLevel logs a message at error level
20 ErrorLevel
21 // PanicLevel logs a message, then panics.
22 PanicLevel
23 // FatalLevel logs a message, then calls os.Exit(1).
24 FatalLevel
25)
26
27// CONSOLE formats the log for the console, mostly used during development
28const CONSOLE = "console"
khenaidoo5c11af72018-07-20 17:21:05 -040029
khenaidoocfee5f42018-07-19 22:47:38 -040030// JSON formats the log using json format, mostly used by an automated logging system consumption
31const JSON = "json"
32
33// Logger represents an abstract logging interface. Any logging implementation used
34// will need to abide by this interface
35type Logger interface {
36 Debug(...interface{})
37 Debugln(...interface{})
38 Debugf(string, ...interface{})
39 Debugw(string, Fields)
40
41 Info(...interface{})
42 Infoln(...interface{})
43 Infof(string, ...interface{})
44 Infow(string, Fields)
45
46 Warn(...interface{})
47 Warnln(...interface{})
48 Warnf(string, ...interface{})
49 Warnw(string, Fields)
50
51 Error(...interface{})
52 Errorln(...interface{})
53 Errorf(string, ...interface{})
54 Errorw(string, Fields)
55
56 Fatal(...interface{})
57 Fatalln(...interface{})
58 Fatalf(string, ...interface{})
59 Fatalw(string, Fields)
60
61 With(Fields) Logger
62}
63
64// Fields is used as key-value pairs for structural logging
65type Fields map[string]interface{}
66
67var defaultLogger *logger
68
69type logger struct {
70 log *zp.SugaredLogger
71 parent *zp.Logger
72}
73
74func parseLevel(l int) zp.AtomicLevel {
75 switch l {
76 case DebugLevel:
77 return zp.NewAtomicLevelAt(zc.DebugLevel)
78 case InfoLevel:
79 return zp.NewAtomicLevelAt(zc.InfoLevel)
80 case WarnLevel:
81 return zp.NewAtomicLevelAt(zc.WarnLevel)
82 case ErrorLevel:
83 return zp.NewAtomicLevelAt(zc.ErrorLevel)
84 case PanicLevel:
85 return zp.NewAtomicLevelAt(zc.PanicLevel)
86 case FatalLevel:
87 return zp.NewAtomicLevelAt(zc.FatalLevel)
88 }
89 return zp.NewAtomicLevelAt(zc.ErrorLevel)
90}
91
92func getDefaultConfig(outputType string, level int, defaultFields Fields) zp.Config {
93 return zp.Config{
94 Level: parseLevel(level),
95 Encoding: outputType,
96 Development: true,
97 OutputPaths: []string{"stdout"},
98 ErrorOutputPaths: []string{"stderr"},
99 InitialFields: defaultFields,
100 EncoderConfig: zc.EncoderConfig{
101 LevelKey: "level",
102 MessageKey: "msg",
103 TimeKey: "ts",
104 StacktraceKey: "stacktrace",
105 LineEnding: zc.DefaultLineEnding,
106 EncodeLevel: zc.LowercaseLevelEncoder,
107 EncodeTime: zc.ISO8601TimeEncoder,
108 EncodeDuration: zc.SecondsDurationEncoder,
109 EncodeCaller: zc.ShortCallerEncoder,
110 },
111 }
112}
113
114// SetLogger needs to be invoked before the logger API can be invoked. This function
115// initialize the default logger (zap's sugaredlogger)
116func SetLogger(outputType string, level int, defaultFields Fields) (Logger, error) {
117
118 // Build a custom config using zap
119 cfg := getDefaultConfig(outputType, level, defaultFields)
120
121 l, err := cfg.Build()
122 if err != nil {
123 return nil, err
124 }
125
126 defaultLogger = &logger{
127 log: l.Sugar(),
128 parent: l,
129 }
130
131 return defaultLogger, nil
132}
133
134// CleanUp flushed any buffered log entries. Applications should take care to call
135// CleanUp before exiting.
136func CleanUp() error {
137 if defaultLogger != nil {
138 if defaultLogger.parent != nil {
139 if err := defaultLogger.parent.Sync(); err != nil {
140 return err
141 }
142 }
143 }
144 return nil
145}
146
147// GetLogger returned the default logger. If SetLogger was not previously invoked then
148// this method will return an error
149func GetLogger() (Logger, error) {
150 if defaultLogger == nil {
151 return nil, errors.New("Uninitialized-logger")
152 }
153 return defaultLogger, nil
154}
155
156func extractFileNameAndLineNumber(skipLevel int) (string, int) {
157 _, file, line, ok := runtime.Caller(skipLevel)
158 var key string
159 if !ok {
160 key = "<???>"
161 line = 1
162 } else {
163 slash := strings.LastIndex(file, "/")
164 key = file[slash+1:]
165 }
166 return key, line
167}
168
169// sourced adds a source field to the logger that contains
170// the file name and line where the logging happened.
171func (l *logger) sourced() *zp.SugaredLogger {
172 key, line := extractFileNameAndLineNumber(3)
173 if strings.HasSuffix(key, "log.go") || strings.HasSuffix(key, "proc.go") {
174 // Go to a lower level
175 key, line = extractFileNameAndLineNumber(2)
176 }
177 if !strings.HasSuffix(key, ".go") {
178 // Go to a higher level
179 key, line = extractFileNameAndLineNumber(4)
180 }
181
182 return l.log.With("caller", fmt.Sprintf("%s:%d", key, line))
183}
184
185//func serializeMap(fields Fields) []interface{} {
186// data := make([]interface{}, len(fields)*2+2)
187// i := 0
188// for k, v := range fields {
189// data[i] = k
190// data[i+1] = v
191// i = i + 2
192// }
193// key, line := extractFileNameAndLineNumber(3)
194// data[i] = "caller"
195// data[i+1] = fmt.Sprintf("%s:%d", key, line)
196//
197// return data
198//}
199
200func serializeMap(fields Fields) []interface{} {
201 data := make([]interface{}, len(fields)*2)
202 i := 0
203 for k, v := range fields {
204 data[i] = k
205 data[i+1] = v
206 i = i + 2
207 }
208 return data
209}
210
211// With returns a logger initialized with the key-value pairs
212func (l logger) With(keysAndValues Fields) Logger {
213 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
214}
215
216// Debug logs a message at level Debug on the standard logger.
217func (l logger) Debug(args ...interface{}) {
218 l.log.Debug(args...)
219}
220
221// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
222func (l logger) Debugln(args ...interface{}) {
223 l.log.Debug(args...)
224}
225
226// Debugw logs a message at level Debug on the standard logger.
227func (l logger) Debugf(format string, args ...interface{}) {
228 l.log.Debugf(format, args...)
229}
230
231// Debugw logs a message with some additional context. The variadic key-value
232// pairs are treated as they are in With.
233func (l logger) Debugw(msg string, keysAndValues Fields) {
234 l.log.Debugw(msg, serializeMap(keysAndValues)...)
235}
236
237// Info logs a message at level Info on the standard logger.
238func (l logger) Info(args ...interface{}) {
239 l.log.Info(args...)
240}
241
242// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
243func (l logger) Infoln(args ...interface{}) {
244 l.log.Info(args...)
245 //msg := fmt.Sprintln(args...)
246 //l.sourced().Info(msg[:len(msg)-1])
247}
248
249// Infof logs a message at level Info on the standard logger.
250func (l logger) Infof(format string, args ...interface{}) {
251 l.log.Infof(format, args...)
252}
253
254// Infow logs a message with some additional context. The variadic key-value
255// pairs are treated as they are in With.
256func (l logger) Infow(msg string, keysAndValues Fields) {
257 l.log.Infow(msg, serializeMap(keysAndValues)...)
258}
259
260// Warn logs a message at level Warn on the standard logger.
261func (l logger) Warn(args ...interface{}) {
262 l.log.Warn(args...)
263}
264
265// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
266func (l logger) Warnln(args ...interface{}) {
267 l.log.Warn(args...)
268}
269
270// Warnf logs a message at level Warn on the standard logger.
271func (l logger) Warnf(format string, args ...interface{}) {
272 l.log.Warnf(format, args...)
273}
274
275// Warnw logs a message with some additional context. The variadic key-value
276// pairs are treated as they are in With.
277func (l logger) Warnw(msg string, keysAndValues Fields) {
278 l.log.Warnw(msg, serializeMap(keysAndValues)...)
279}
280
281// Error logs a message at level Error on the standard logger.
282func (l logger) Error(args ...interface{}) {
283 l.log.Error(args...)
284}
285
286// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
287func (l logger) Errorln(args ...interface{}) {
288 l.log.Error(args...)
289}
290
291// Errorf logs a message at level Error on the standard logger.
292func (l logger) Errorf(format string, args ...interface{}) {
293 l.log.Errorf(format, args...)
294}
295
296// Errorw logs a message with some additional context. The variadic key-value
297// pairs are treated as they are in With.
298func (l logger) Errorw(msg string, keysAndValues Fields) {
299 l.log.Errorw(msg, serializeMap(keysAndValues)...)
300}
301
302// Fatal logs a message at level Fatal on the standard logger.
303func (l logger) Fatal(args ...interface{}) {
304 l.log.Fatal(args...)
305}
306
307// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
308func (l logger) Fatalln(args ...interface{}) {
309 l.log.Fatal(args...)
310}
311
312// Fatalf logs a message at level Fatal on the standard logger.
313func (l logger) Fatalf(format string, args ...interface{}) {
314 l.log.Fatalf(format, args...)
315}
316
317// Fatalw logs a message with some additional context. The variadic key-value
318// pairs are treated as they are in With.
319func (l logger) Fatalw(msg string, keysAndValues Fields) {
320 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
321}
322
323// With returns a logger initialized with the key-value pairs
324func With(keysAndValues Fields) Logger {
325 return logger{log: defaultLogger.sourced().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
326}
327
328// Debug logs a message at level Debug on the standard logger.
329func Debug(args ...interface{}) {
330 defaultLogger.sourced().Debug(args...)
331}
332
333// Debugln logs a message at level Debug on the standard logger.
334func Debugln(args ...interface{}) {
335 defaultLogger.sourced().Debug(args...)
336}
337
338// Debugf logs a message at level Debug on the standard logger.
339func Debugf(format string, args ...interface{}) {
340 defaultLogger.sourced().Debugf(format, args...)
341}
342
343// Debugw logs a message with some additional context. The variadic key-value
344// pairs are treated as they are in With.
345func Debugw(msg string, keysAndValues Fields) {
346 defaultLogger.sourced().Debugw(msg, serializeMap(keysAndValues)...)
347}
348
349// Info logs a message at level Info on the standard logger.
350func Info(args ...interface{}) {
351 defaultLogger.sourced().Info(args...)
352}
353
354// Infoln logs a message at level Info on the standard logger.
355func Infoln(args ...interface{}) {
356 defaultLogger.sourced().Info(args...)
357}
358
359// Infof logs a message at level Info on the standard logger.
360func Infof(format string, args ...interface{}) {
361 defaultLogger.sourced().Infof(format, args...)
362}
363
364//Infow logs a message with some additional context. The variadic key-value
365//pairs are treated as they are in With.
366func Infow(msg string, keysAndValues Fields) {
367 defaultLogger.sourced().Infow(msg, serializeMap(keysAndValues)...)
368}
369
370// Warn logs a message at level Warn on the standard logger.
371func Warn(args ...interface{}) {
372 defaultLogger.sourced().Warn(args...)
373}
374
375// Warnln logs a message at level Warn on the standard logger.
376func Warnln(args ...interface{}) {
377 defaultLogger.sourced().Warn(args...)
378}
379
380// Warnf logs a message at level Warn on the standard logger.
381func Warnf(format string, args ...interface{}) {
382 defaultLogger.sourced().Warnf(format, args...)
383}
384
385// Warnw logs a message with some additional context. The variadic key-value
386// pairs are treated as they are in With.
387func Warnw(msg string, keysAndValues Fields) {
388 defaultLogger.sourced().Warnw(msg, serializeMap(keysAndValues)...)
389}
390
391// Error logs a message at level Error on the standard logger.
392func Error(args ...interface{}) {
393 defaultLogger.sourced().Error(args...)
394}
395
396// Errorln logs a message at level Error on the standard logger.
397func Errorln(args ...interface{}) {
398 defaultLogger.sourced().Error(args...)
399}
400
401// Errorf logs a message at level Error on the standard logger.
402func Errorf(format string, args ...interface{}) {
403 defaultLogger.sourced().Errorf(format, args...)
404}
405
406// Errorw logs a message with some additional context. The variadic key-value
407// pairs are treated as they are in With.
408func Errorw(msg string, keysAndValues Fields) {
409 defaultLogger.sourced().Errorw(msg, serializeMap(keysAndValues)...)
410}
411
412// Fatal logs a message at level Fatal on the standard logger.
413func Fatal(args ...interface{}) {
414 defaultLogger.sourced().Fatal(args...)
415}
416
417// Fatalln logs a message at level Fatal on the standard logger.
418func Fatalln(args ...interface{}) {
419 defaultLogger.sourced().Fatal(args...)
420}
421
422// Fatalf logs a message at level Fatal on the standard logger.
423func Fatalf(format string, args ...interface{}) {
424 defaultLogger.sourced().Fatalf(format, args...)
425}
426
427// Fatalw logs a message with some additional context. The variadic key-value
428// pairs are treated as they are in With.
429func Fatalw(msg string, keysAndValues Fields) {
430 defaultLogger.sourced().Fatalw(msg, serializeMap(keysAndValues)...)
431}