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