blob: d751c34c09e5488563ec37c44c79ebee1f401f21 [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
113// SetLogger needs to be invoked before the logger API can be invoked. This function
114// initialize the default logger (zap's sugaredlogger)
115func SetLogger(outputType string, level int, defaultFields Fields) (Logger, error) {
116
117 // Build a custom config using zap
118 cfg := getDefaultConfig(outputType, level, defaultFields)
119
120 l, err := cfg.Build()
121 if err != nil {
122 return nil, err
123 }
124
125 defaultLogger = &logger{
126 log: l.Sugar(),
127 parent: l,
128 }
129
130 return defaultLogger, nil
131}
132
133// CleanUp flushed any buffered log entries. Applications should take care to call
134// CleanUp before exiting.
135func CleanUp() error {
136 if defaultLogger != nil {
137 if defaultLogger.parent != nil {
138 if err := defaultLogger.parent.Sync(); err != nil {
139 return err
140 }
141 }
142 }
143 return nil
144}
145
146// GetLogger returned the default logger. If SetLogger was not previously invoked then
147// this method will return an error
148func GetLogger() (Logger, error) {
149 if defaultLogger == nil {
khenaidooabad44c2018-08-03 16:58:35 -0400150 // Setup the logger with default values - debug level,
151 SetLogger(JSON, 0, Fields{"instanceId": "default-logger"})
152 //return nil, errors.New("Uninitialized-logger")
khenaidoocfee5f42018-07-19 22:47:38 -0400153 }
154 return defaultLogger, nil
155}
156
157func extractFileNameAndLineNumber(skipLevel int) (string, int) {
158 _, file, line, ok := runtime.Caller(skipLevel)
159 var key string
160 if !ok {
161 key = "<???>"
162 line = 1
163 } else {
164 slash := strings.LastIndex(file, "/")
165 key = file[slash+1:]
166 }
167 return key, line
168}
169
170// sourced adds a source field to the logger that contains
171// the file name and line where the logging happened.
172func (l *logger) sourced() *zp.SugaredLogger {
173 key, line := extractFileNameAndLineNumber(3)
174 if strings.HasSuffix(key, "log.go") || strings.HasSuffix(key, "proc.go") {
175 // Go to a lower level
176 key, line = extractFileNameAndLineNumber(2)
177 }
178 if !strings.HasSuffix(key, ".go") {
179 // Go to a higher level
180 key, line = extractFileNameAndLineNumber(4)
181 }
182
183 return l.log.With("caller", fmt.Sprintf("%s:%d", key, line))
184}
185
186//func serializeMap(fields Fields) []interface{} {
187// data := make([]interface{}, len(fields)*2+2)
188// i := 0
189// for k, v := range fields {
190// data[i] = k
191// data[i+1] = v
192// i = i + 2
193// }
194// key, line := extractFileNameAndLineNumber(3)
195// data[i] = "caller"
196// data[i+1] = fmt.Sprintf("%s:%d", key, line)
197//
198// return data
199//}
200
201func serializeMap(fields Fields) []interface{} {
202 data := make([]interface{}, len(fields)*2)
203 i := 0
204 for k, v := range fields {
205 data[i] = k
206 data[i+1] = v
207 i = i + 2
208 }
209 return data
210}
211
212// With returns a logger initialized with the key-value pairs
213func (l logger) With(keysAndValues Fields) Logger {
214 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
215}
216
217// Debug logs a message at level Debug on the standard logger.
218func (l logger) Debug(args ...interface{}) {
219 l.log.Debug(args...)
220}
221
222// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
223func (l logger) Debugln(args ...interface{}) {
224 l.log.Debug(args...)
225}
226
227// Debugw logs a message at level Debug on the standard logger.
228func (l logger) Debugf(format string, args ...interface{}) {
229 l.log.Debugf(format, args...)
230}
231
232// Debugw logs a message with some additional context. The variadic key-value
233// pairs are treated as they are in With.
234func (l logger) Debugw(msg string, keysAndValues Fields) {
235 l.log.Debugw(msg, serializeMap(keysAndValues)...)
236}
237
238// Info logs a message at level Info on the standard logger.
239func (l logger) Info(args ...interface{}) {
240 l.log.Info(args...)
241}
242
243// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
244func (l logger) Infoln(args ...interface{}) {
245 l.log.Info(args...)
246 //msg := fmt.Sprintln(args...)
247 //l.sourced().Info(msg[:len(msg)-1])
248}
249
250// Infof logs a message at level Info on the standard logger.
251func (l logger) Infof(format string, args ...interface{}) {
252 l.log.Infof(format, args...)
253}
254
255// Infow logs a message with some additional context. The variadic key-value
256// pairs are treated as they are in With.
257func (l logger) Infow(msg string, keysAndValues Fields) {
258 l.log.Infow(msg, serializeMap(keysAndValues)...)
259}
260
261// Warn logs a message at level Warn on the standard logger.
262func (l logger) Warn(args ...interface{}) {
263 l.log.Warn(args...)
264}
265
266// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
267func (l logger) Warnln(args ...interface{}) {
268 l.log.Warn(args...)
269}
270
271// Warnf logs a message at level Warn on the standard logger.
272func (l logger) Warnf(format string, args ...interface{}) {
273 l.log.Warnf(format, args...)
274}
275
276// Warnw logs a message with some additional context. The variadic key-value
277// pairs are treated as they are in With.
278func (l logger) Warnw(msg string, keysAndValues Fields) {
279 l.log.Warnw(msg, serializeMap(keysAndValues)...)
280}
281
282// Error logs a message at level Error on the standard logger.
283func (l logger) Error(args ...interface{}) {
284 l.log.Error(args...)
285}
286
287// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
288func (l logger) Errorln(args ...interface{}) {
289 l.log.Error(args...)
290}
291
292// Errorf logs a message at level Error on the standard logger.
293func (l logger) Errorf(format string, args ...interface{}) {
294 l.log.Errorf(format, args...)
295}
296
297// Errorw logs a message with some additional context. The variadic key-value
298// pairs are treated as they are in With.
299func (l logger) Errorw(msg string, keysAndValues Fields) {
300 l.log.Errorw(msg, serializeMap(keysAndValues)...)
301}
302
303// Fatal logs a message at level Fatal on the standard logger.
304func (l logger) Fatal(args ...interface{}) {
305 l.log.Fatal(args...)
306}
307
308// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
309func (l logger) Fatalln(args ...interface{}) {
310 l.log.Fatal(args...)
311}
312
313// Fatalf logs a message at level Fatal on the standard logger.
314func (l logger) Fatalf(format string, args ...interface{}) {
315 l.log.Fatalf(format, args...)
316}
317
318// Fatalw logs a message with some additional context. The variadic key-value
319// pairs are treated as they are in With.
320func (l logger) Fatalw(msg string, keysAndValues Fields) {
321 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
322}
323
324// With returns a logger initialized with the key-value pairs
325func With(keysAndValues Fields) Logger {
326 return logger{log: defaultLogger.sourced().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
327}
328
329// Debug logs a message at level Debug on the standard logger.
330func Debug(args ...interface{}) {
331 defaultLogger.sourced().Debug(args...)
332}
333
334// Debugln logs a message at level Debug on the standard logger.
335func Debugln(args ...interface{}) {
336 defaultLogger.sourced().Debug(args...)
337}
338
339// Debugf logs a message at level Debug on the standard logger.
340func Debugf(format string, args ...interface{}) {
341 defaultLogger.sourced().Debugf(format, args...)
342}
343
344// Debugw logs a message with some additional context. The variadic key-value
345// pairs are treated as they are in With.
346func Debugw(msg string, keysAndValues Fields) {
347 defaultLogger.sourced().Debugw(msg, serializeMap(keysAndValues)...)
348}
349
350// Info logs a message at level Info on the standard logger.
351func Info(args ...interface{}) {
352 defaultLogger.sourced().Info(args...)
353}
354
355// Infoln logs a message at level Info on the standard logger.
356func Infoln(args ...interface{}) {
357 defaultLogger.sourced().Info(args...)
358}
359
360// Infof logs a message at level Info on the standard logger.
361func Infof(format string, args ...interface{}) {
362 defaultLogger.sourced().Infof(format, args...)
363}
364
365//Infow logs a message with some additional context. The variadic key-value
366//pairs are treated as they are in With.
367func Infow(msg string, keysAndValues Fields) {
368 defaultLogger.sourced().Infow(msg, serializeMap(keysAndValues)...)
369}
370
371// Warn logs a message at level Warn on the standard logger.
372func Warn(args ...interface{}) {
373 defaultLogger.sourced().Warn(args...)
374}
375
376// Warnln logs a message at level Warn on the standard logger.
377func Warnln(args ...interface{}) {
378 defaultLogger.sourced().Warn(args...)
379}
380
381// Warnf logs a message at level Warn on the standard logger.
382func Warnf(format string, args ...interface{}) {
383 defaultLogger.sourced().Warnf(format, args...)
384}
385
386// Warnw logs a message with some additional context. The variadic key-value
387// pairs are treated as they are in With.
388func Warnw(msg string, keysAndValues Fields) {
389 defaultLogger.sourced().Warnw(msg, serializeMap(keysAndValues)...)
390}
391
392// Error logs a message at level Error on the standard logger.
393func Error(args ...interface{}) {
394 defaultLogger.sourced().Error(args...)
395}
396
397// Errorln logs a message at level Error on the standard logger.
398func Errorln(args ...interface{}) {
399 defaultLogger.sourced().Error(args...)
400}
401
402// Errorf logs a message at level Error on the standard logger.
403func Errorf(format string, args ...interface{}) {
404 defaultLogger.sourced().Errorf(format, args...)
405}
406
407// Errorw logs a message with some additional context. The variadic key-value
408// pairs are treated as they are in With.
409func Errorw(msg string, keysAndValues Fields) {
410 defaultLogger.sourced().Errorw(msg, serializeMap(keysAndValues)...)
411}
412
413// Fatal logs a message at level Fatal on the standard logger.
414func Fatal(args ...interface{}) {
415 defaultLogger.sourced().Fatal(args...)
416}
417
418// Fatalln logs a message at level Fatal on the standard logger.
419func Fatalln(args ...interface{}) {
420 defaultLogger.sourced().Fatal(args...)
421}
422
423// Fatalf logs a message at level Fatal on the standard logger.
424func Fatalf(format string, args ...interface{}) {
425 defaultLogger.sourced().Fatalf(format, args...)
426}
427
428// Fatalw logs a message with some additional context. The variadic key-value
429// pairs are treated as they are in With.
430func Fatalw(msg string, keysAndValues Fields) {
431 defaultLogger.sourced().Fatalw(msg, serializeMap(keysAndValues)...)
432}