blob: 4bb31c0f6daaef525a349457db8b055364e206a3 [file] [log] [blame]
khenaidoocfee5f42018-07-19 22:47:38 -04001package log
2
3import (
4 "errors"
5 zp "go.uber.org/zap"
6 zc "go.uber.org/zap/zapcore"
7 "runtime"
8 "strings"
9 "fmt"
10)
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"
29// 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 {
150 return nil, errors.New("Uninitialized-logger")
151 }
152 return defaultLogger, nil
153}
154
155func extractFileNameAndLineNumber(skipLevel int) (string, int) {
156 _, file, line, ok := runtime.Caller(skipLevel)
157 var key string
158 if !ok {
159 key = "<???>"
160 line = 1
161 } else {
162 slash := strings.LastIndex(file, "/")
163 key = file[slash+1:]
164 }
165 return key, line
166}
167
168// sourced adds a source field to the logger that contains
169// the file name and line where the logging happened.
170func (l *logger) sourced() *zp.SugaredLogger {
171 key, line := extractFileNameAndLineNumber(3)
172 if strings.HasSuffix(key, "log.go") || strings.HasSuffix(key, "proc.go") {
173 // Go to a lower level
174 key, line = extractFileNameAndLineNumber(2)
175 }
176 if !strings.HasSuffix(key, ".go") {
177 // Go to a higher level
178 key, line = extractFileNameAndLineNumber(4)
179 }
180
181 return l.log.With("caller", fmt.Sprintf("%s:%d", key, line))
182}
183
184//func serializeMap(fields Fields) []interface{} {
185// data := make([]interface{}, len(fields)*2+2)
186// i := 0
187// for k, v := range fields {
188// data[i] = k
189// data[i+1] = v
190// i = i + 2
191// }
192// key, line := extractFileNameAndLineNumber(3)
193// data[i] = "caller"
194// data[i+1] = fmt.Sprintf("%s:%d", key, line)
195//
196// return data
197//}
198
199func serializeMap(fields Fields) []interface{} {
200 data := make([]interface{}, len(fields)*2)
201 i := 0
202 for k, v := range fields {
203 data[i] = k
204 data[i+1] = v
205 i = i + 2
206 }
207 return data
208}
209
210// With returns a logger initialized with the key-value pairs
211func (l logger) With(keysAndValues Fields) Logger {
212 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
213}
214
215// Debug logs a message at level Debug on the standard logger.
216func (l logger) Debug(args ...interface{}) {
217 l.log.Debug(args...)
218}
219
220// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
221func (l logger) Debugln(args ...interface{}) {
222 l.log.Debug(args...)
223}
224
225// Debugw logs a message at level Debug on the standard logger.
226func (l logger) Debugf(format string, args ...interface{}) {
227 l.log.Debugf(format, args...)
228}
229
230// Debugw logs a message with some additional context. The variadic key-value
231// pairs are treated as they are in With.
232func (l logger) Debugw(msg string, keysAndValues Fields) {
233 l.log.Debugw(msg, serializeMap(keysAndValues)...)
234}
235
236// Info logs a message at level Info on the standard logger.
237func (l logger) Info(args ...interface{}) {
238 l.log.Info(args...)
239}
240
241// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
242func (l logger) Infoln(args ...interface{}) {
243 l.log.Info(args...)
244 //msg := fmt.Sprintln(args...)
245 //l.sourced().Info(msg[:len(msg)-1])
246}
247
248// Infof logs a message at level Info on the standard logger.
249func (l logger) Infof(format string, args ...interface{}) {
250 l.log.Infof(format, args...)
251}
252
253// Infow logs a message with some additional context. The variadic key-value
254// pairs are treated as they are in With.
255func (l logger) Infow(msg string, keysAndValues Fields) {
256 l.log.Infow(msg, serializeMap(keysAndValues)...)
257}
258
259// Warn logs a message at level Warn on the standard logger.
260func (l logger) Warn(args ...interface{}) {
261 l.log.Warn(args...)
262}
263
264// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
265func (l logger) Warnln(args ...interface{}) {
266 l.log.Warn(args...)
267}
268
269// Warnf logs a message at level Warn on the standard logger.
270func (l logger) Warnf(format string, args ...interface{}) {
271 l.log.Warnf(format, args...)
272}
273
274// Warnw logs a message with some additional context. The variadic key-value
275// pairs are treated as they are in With.
276func (l logger) Warnw(msg string, keysAndValues Fields) {
277 l.log.Warnw(msg, serializeMap(keysAndValues)...)
278}
279
280// Error logs a message at level Error on the standard logger.
281func (l logger) Error(args ...interface{}) {
282 l.log.Error(args...)
283}
284
285// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
286func (l logger) Errorln(args ...interface{}) {
287 l.log.Error(args...)
288}
289
290// Errorf logs a message at level Error on the standard logger.
291func (l logger) Errorf(format string, args ...interface{}) {
292 l.log.Errorf(format, args...)
293}
294
295// Errorw logs a message with some additional context. The variadic key-value
296// pairs are treated as they are in With.
297func (l logger) Errorw(msg string, keysAndValues Fields) {
298 l.log.Errorw(msg, serializeMap(keysAndValues)...)
299}
300
301// Fatal logs a message at level Fatal on the standard logger.
302func (l logger) Fatal(args ...interface{}) {
303 l.log.Fatal(args...)
304}
305
306// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
307func (l logger) Fatalln(args ...interface{}) {
308 l.log.Fatal(args...)
309}
310
311// Fatalf logs a message at level Fatal on the standard logger.
312func (l logger) Fatalf(format string, args ...interface{}) {
313 l.log.Fatalf(format, args...)
314}
315
316// Fatalw logs a message with some additional context. The variadic key-value
317// pairs are treated as they are in With.
318func (l logger) Fatalw(msg string, keysAndValues Fields) {
319 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
320}
321
322// With returns a logger initialized with the key-value pairs
323func With(keysAndValues Fields) Logger {
324 return logger{log: defaultLogger.sourced().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
325}
326
327// Debug logs a message at level Debug on the standard logger.
328func Debug(args ...interface{}) {
329 defaultLogger.sourced().Debug(args...)
330}
331
332// Debugln logs a message at level Debug on the standard logger.
333func Debugln(args ...interface{}) {
334 defaultLogger.sourced().Debug(args...)
335}
336
337// Debugf logs a message at level Debug on the standard logger.
338func Debugf(format string, args ...interface{}) {
339 defaultLogger.sourced().Debugf(format, args...)
340}
341
342// Debugw logs a message with some additional context. The variadic key-value
343// pairs are treated as they are in With.
344func Debugw(msg string, keysAndValues Fields) {
345 defaultLogger.sourced().Debugw(msg, serializeMap(keysAndValues)...)
346}
347
348// Info logs a message at level Info on the standard logger.
349func Info(args ...interface{}) {
350 defaultLogger.sourced().Info(args...)
351}
352
353// Infoln logs a message at level Info on the standard logger.
354func Infoln(args ...interface{}) {
355 defaultLogger.sourced().Info(args...)
356}
357
358// Infof logs a message at level Info on the standard logger.
359func Infof(format string, args ...interface{}) {
360 defaultLogger.sourced().Infof(format, args...)
361}
362
363//Infow logs a message with some additional context. The variadic key-value
364//pairs are treated as they are in With.
365func Infow(msg string, keysAndValues Fields) {
366 defaultLogger.sourced().Infow(msg, serializeMap(keysAndValues)...)
367}
368
369// Warn logs a message at level Warn on the standard logger.
370func Warn(args ...interface{}) {
371 defaultLogger.sourced().Warn(args...)
372}
373
374// Warnln logs a message at level Warn on the standard logger.
375func Warnln(args ...interface{}) {
376 defaultLogger.sourced().Warn(args...)
377}
378
379// Warnf logs a message at level Warn on the standard logger.
380func Warnf(format string, args ...interface{}) {
381 defaultLogger.sourced().Warnf(format, args...)
382}
383
384// Warnw logs a message with some additional context. The variadic key-value
385// pairs are treated as they are in With.
386func Warnw(msg string, keysAndValues Fields) {
387 defaultLogger.sourced().Warnw(msg, serializeMap(keysAndValues)...)
388}
389
390// Error logs a message at level Error on the standard logger.
391func Error(args ...interface{}) {
392 defaultLogger.sourced().Error(args...)
393}
394
395// Errorln logs a message at level Error on the standard logger.
396func Errorln(args ...interface{}) {
397 defaultLogger.sourced().Error(args...)
398}
399
400// Errorf logs a message at level Error on the standard logger.
401func Errorf(format string, args ...interface{}) {
402 defaultLogger.sourced().Errorf(format, args...)
403}
404
405// Errorw logs a message with some additional context. The variadic key-value
406// pairs are treated as they are in With.
407func Errorw(msg string, keysAndValues Fields) {
408 defaultLogger.sourced().Errorw(msg, serializeMap(keysAndValues)...)
409}
410
411// Fatal logs a message at level Fatal on the standard logger.
412func Fatal(args ...interface{}) {
413 defaultLogger.sourced().Fatal(args...)
414}
415
416// Fatalln logs a message at level Fatal on the standard logger.
417func Fatalln(args ...interface{}) {
418 defaultLogger.sourced().Fatal(args...)
419}
420
421// Fatalf logs a message at level Fatal on the standard logger.
422func Fatalf(format string, args ...interface{}) {
423 defaultLogger.sourced().Fatalf(format, args...)
424}
425
426// Fatalw logs a message with some additional context. The variadic key-value
427// pairs are treated as they are in With.
428func Fatalw(msg string, keysAndValues Fields) {
429 defaultLogger.sourced().Fatalw(msg, serializeMap(keysAndValues)...)
430}