blob: e86ba0dfc61872e14eb1999dfaabd049dcf2c855 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
khenaidoocfee5f42018-07-19 22:47:38 -040016package log
17
18import (
khenaidoo5c11af72018-07-20 17:21:05 -040019 "fmt"
khenaidoocfee5f42018-07-19 22:47:38 -040020 zp "go.uber.org/zap"
21 zc "go.uber.org/zap/zapcore"
khenaidoob9203542018-09-17 22:56:37 -040022 "path"
khenaidoocfee5f42018-07-19 22:47:38 -040023 "runtime"
24 "strings"
khenaidoocfee5f42018-07-19 22:47:38 -040025)
26
27const (
28 // DebugLevel logs a message at debug level
29 DebugLevel = iota
30 // InfoLevel logs a message at info level
31 InfoLevel
32 // WarnLevel logs a message at warning level
33 WarnLevel
34 // ErrorLevel logs a message at error level
35 ErrorLevel
36 // PanicLevel logs a message, then panics.
37 PanicLevel
38 // FatalLevel logs a message, then calls os.Exit(1).
39 FatalLevel
40)
41
42// CONSOLE formats the log for the console, mostly used during development
43const CONSOLE = "console"
khenaidoo5c11af72018-07-20 17:21:05 -040044
khenaidoocfee5f42018-07-19 22:47:38 -040045// JSON formats the log using json format, mostly used by an automated logging system consumption
46const JSON = "json"
47
48// Logger represents an abstract logging interface. Any logging implementation used
49// will need to abide by this interface
50type Logger interface {
51 Debug(...interface{})
52 Debugln(...interface{})
53 Debugf(string, ...interface{})
54 Debugw(string, Fields)
55
56 Info(...interface{})
57 Infoln(...interface{})
58 Infof(string, ...interface{})
59 Infow(string, Fields)
60
61 Warn(...interface{})
62 Warnln(...interface{})
63 Warnf(string, ...interface{})
64 Warnw(string, Fields)
65
66 Error(...interface{})
67 Errorln(...interface{})
68 Errorf(string, ...interface{})
69 Errorw(string, Fields)
70
71 Fatal(...interface{})
72 Fatalln(...interface{})
73 Fatalf(string, ...interface{})
74 Fatalw(string, Fields)
75
76 With(Fields) Logger
77}
78
79// Fields is used as key-value pairs for structural logging
80type Fields map[string]interface{}
81
82var defaultLogger *logger
khenaidoob9203542018-09-17 22:56:37 -040083var cfg zp.Config
84
85var loggers map[string]*logger
86var cfgs map[string]zp.Config
khenaidoocfee5f42018-07-19 22:47:38 -040087
88type logger struct {
89 log *zp.SugaredLogger
90 parent *zp.Logger
91}
92
93func parseLevel(l int) zp.AtomicLevel {
94 switch l {
95 case DebugLevel:
96 return zp.NewAtomicLevelAt(zc.DebugLevel)
97 case InfoLevel:
98 return zp.NewAtomicLevelAt(zc.InfoLevel)
99 case WarnLevel:
100 return zp.NewAtomicLevelAt(zc.WarnLevel)
101 case ErrorLevel:
102 return zp.NewAtomicLevelAt(zc.ErrorLevel)
103 case PanicLevel:
104 return zp.NewAtomicLevelAt(zc.PanicLevel)
105 case FatalLevel:
106 return zp.NewAtomicLevelAt(zc.FatalLevel)
107 }
108 return zp.NewAtomicLevelAt(zc.ErrorLevel)
109}
110
111func getDefaultConfig(outputType string, level int, defaultFields Fields) zp.Config {
112 return zp.Config{
113 Level: parseLevel(level),
114 Encoding: outputType,
115 Development: true,
116 OutputPaths: []string{"stdout"},
117 ErrorOutputPaths: []string{"stderr"},
118 InitialFields: defaultFields,
119 EncoderConfig: zc.EncoderConfig{
120 LevelKey: "level",
121 MessageKey: "msg",
122 TimeKey: "ts",
123 StacktraceKey: "stacktrace",
124 LineEnding: zc.DefaultLineEnding,
125 EncodeLevel: zc.LowercaseLevelEncoder,
126 EncodeTime: zc.ISO8601TimeEncoder,
127 EncodeDuration: zc.SecondsDurationEncoder,
128 EncodeCaller: zc.ShortCallerEncoder,
129 },
130 }
131}
132
133// SetLogger needs to be invoked before the logger API can be invoked. This function
134// initialize the default logger (zap's sugaredlogger)
khenaidoob9203542018-09-17 22:56:37 -0400135func SetDefaultLogger(outputType string, level int, defaultFields Fields) (Logger, error) {
khenaidoocfee5f42018-07-19 22:47:38 -0400136 // Build a custom config using zap
khenaidood4d922e2018-08-03 22:35:16 -0400137 cfg = getDefaultConfig(outputType, level, defaultFields)
khenaidoocfee5f42018-07-19 22:47:38 -0400138
139 l, err := cfg.Build()
140 if err != nil {
141 return nil, err
142 }
143
144 defaultLogger = &logger{
145 log: l.Sugar(),
146 parent: l,
147 }
148
149 return defaultLogger, nil
150}
151
khenaidoob9203542018-09-17 22:56:37 -0400152func SetPackageLevelLoggers(outputType string, level int, defaultFields Fields, pkgNames []string) error {
153 cfgs = make(map[string]zp.Config)
154 loggers = make(map[string]*logger)
155 for _, pkg := range pkgNames {
156 // Build a custom config using zap - for now initialzie all packages uses the same config
157 cfgs[pkg] = getDefaultConfig(outputType, level, defaultFields)
158
159 l, err := cfgs[pkg].Build()
160 if err != nil {
161 return err
162 }
163
164 loggers[pkg] = &logger{
165 log: l.Sugar(),
166 parent: l,
167 }
168 }
169
170 return nil
171}
172
173func AddPackage(outputType string, level int, defaultFields Fields) error {
174 if cfgs == nil {
175 cfgs = make(map[string]zp.Config)
176 }
177 if loggers == nil {
178 loggers = make(map[string]*logger)
179 }
180 pkgName, _, _, _ := getCallerInfo()
181
182 if _, exist := cfgs[pkgName]; exist {
183 return nil
184 }
185 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
186
187 l, err := cfgs[pkgName].Build()
188 if err != nil {
189 return err
190 }
191
192 loggers[pkgName] = &logger{
193 log: l.Sugar(),
194 parent: l,
195 }
196 return nil
197}
198
199func UpdateAllLoggers(defaultFields Fields) error {
200 for pkgName, cfg := range cfgs {
201 for k, v := range defaultFields {
202 if cfg.InitialFields == nil {
203 cfg.InitialFields = make(map[string]interface{})
204 }
205 cfg.InitialFields[k] = v
206 }
207 l, err := cfg.Build()
208 if err != nil {
209 return err
210 }
211
212 loggers[pkgName] = &logger{
213 log: l.Sugar(),
214 parent: l,
215 }
216 }
217 return nil
218}
219
220//func SetDefaultLoglevel(level int) {
221// switch level {
222// case DebugLevel:
223// cfg.Level.SetLevel(zc.DebugLevel)
224// case InfoLevel:
225// cfg.Level.SetLevel(zc.InfoLevel)
226// case WarnLevel:
227// cfg.Level.SetLevel(zc.WarnLevel)
228// case ErrorLevel:
229// cfg.Level.SetLevel(zc.ErrorLevel)
230// case PanicLevel:
231// cfg.Level.SetLevel(zc.PanicLevel)
232// case FatalLevel:
233// cfg.Level.SetLevel(zc.FatalLevel)
234// default:
235// cfg.Level.SetLevel(zc.ErrorLevel)
236// }
237//}
238
239func SetPackageLogLevel(packageName string, level int) {
240 // Get proper config
241 if cfg, ok := cfgs[packageName]; ok {
242 switch level {
243 case DebugLevel:
244 cfg.Level.SetLevel(zc.DebugLevel)
245 case InfoLevel:
246 cfg.Level.SetLevel(zc.InfoLevel)
247 case WarnLevel:
248 cfg.Level.SetLevel(zc.WarnLevel)
249 case ErrorLevel:
250 cfg.Level.SetLevel(zc.ErrorLevel)
251 case PanicLevel:
252 cfg.Level.SetLevel(zc.PanicLevel)
253 case FatalLevel:
254 cfg.Level.SetLevel(zc.FatalLevel)
255 default:
256 cfg.Level.SetLevel(zc.ErrorLevel)
257 }
khenaidood4d922e2018-08-03 22:35:16 -0400258 }
259}
260
khenaidoocfee5f42018-07-19 22:47:38 -0400261// CleanUp flushed any buffered log entries. Applications should take care to call
262// CleanUp before exiting.
263func CleanUp() error {
khenaidoob9203542018-09-17 22:56:37 -0400264 for _, logger := range loggers {
265 if logger != nil {
266 if logger.parent != nil {
267 if err := logger.parent.Sync(); err != nil {
268 return err
269 }
270 }
271 }
272 }
khenaidoocfee5f42018-07-19 22:47:38 -0400273 if defaultLogger != nil {
274 if defaultLogger.parent != nil {
275 if err := defaultLogger.parent.Sync(); err != nil {
276 return err
277 }
278 }
279 }
280 return nil
281}
282
283// GetLogger returned the default logger. If SetLogger was not previously invoked then
284// this method will return an error
khenaidoob9203542018-09-17 22:56:37 -0400285//func GetLogger() (Logger, error) {
286// if defaultLogger == nil {
287// // Setup the logger with default values - debug level,
288// SetDefaultLogger(JSON, 0, Fields{"instanceId": "default-logger"})
289// //return nil, errors.New("Uninitialized-logger")
290// }
291// return defaultLogger, nil
292//}
khenaidoocfee5f42018-07-19 22:47:38 -0400293
khenaidoob9203542018-09-17 22:56:37 -0400294//func extractFileNameAndLineNumber(skipLevel int) (string, int) {
295// _, file, line, ok := runtime.Caller(skipLevel)
296// var key string
297// if !ok {
298// key = "<???>"
299// line = 1
300// } else {
301// slash := strings.LastIndex(file, "/")
302// key = file[slash+1:]
303// }
304// return key, line
305//}
khenaidoocfee5f42018-07-19 22:47:38 -0400306
307// sourced adds a source field to the logger that contains
308// the file name and line where the logging happened.
khenaidoob9203542018-09-17 22:56:37 -0400309//func (l *logger) sourced() *zp.SugaredLogger {
310// key, line := extractFileNameAndLineNumber(3)
311// if strings.HasSuffix(key, "log.go") || strings.HasSuffix(key, "proc.go") {
312// // Go to a lower level
313// key, line = extractFileNameAndLineNumber(2)
314// }
315// if !strings.HasSuffix(key, ".go") {
316// // Go to a higher level
317// key, line = extractFileNameAndLineNumber(4)
318// }
319//
320// return l.log.With("caller", fmt.Sprintf("%s:%d", key, line))
321//}
322
323func retrieveCallInfo(skiplevel int) (string, string, string, int) {
324 pc, file, line, _ := runtime.Caller(skiplevel)
325 _, fileName := path.Split(file)
326 parts := strings.Split(runtime.FuncForPC(pc).Name(), ".")
327 pl := len(parts)
328 packageName := ""
329 funcName := parts[pl-1]
330
331 if parts[pl-2][0] == '(' {
332 //funcName = parts[pl-2] + "." + funcName
333 packageName = strings.Join(parts[0:pl-2], ".")
334 } else {
335 packageName = strings.Join(parts[0:pl-1], ".")
khenaidoocfee5f42018-07-19 22:47:38 -0400336 }
337
khenaidoob9203542018-09-17 22:56:37 -0400338 return packageName, fileName, funcName, line
khenaidoocfee5f42018-07-19 22:47:38 -0400339}
340
khenaidoob9203542018-09-17 22:56:37 -0400341func getCallerInfo() (string, string, string, int) {
342 packageName, fileName, funcName, line := retrieveCallInfo(3)
343
344 if strings.HasSuffix(funcName, "log.go") || strings.HasSuffix(funcName, "proc.go") || strings.HasSuffix(packageName, ".init") {
345 // Go to a lower level
346 packageName, fileName, funcName, line = retrieveCallInfo(2)
347 }
348 if !strings.HasSuffix(funcName, ".go") {
349 // Go to a higher level
350 packageName, fileName, funcName, line = retrieveCallInfo(4)
351 }
352
353 if strings.HasSuffix(fileName, ".go") {
354 fileName = strings.TrimSuffix(fileName, ".go")
355 }
356 return packageName, fileName, funcName, line
357}
358
359func getPackageLevelLogger() *zp.SugaredLogger {
360 pkgName, fileName, funcName, line := getCallerInfo()
361 if _, exist := loggers[pkgName]; exist {
362 return loggers[pkgName].log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
363 }
364 return defaultLogger.log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
365}
khenaidoocfee5f42018-07-19 22:47:38 -0400366
367func serializeMap(fields Fields) []interface{} {
368 data := make([]interface{}, len(fields)*2)
369 i := 0
370 for k, v := range fields {
371 data[i] = k
372 data[i+1] = v
373 i = i + 2
374 }
375 return data
376}
377
378// With returns a logger initialized with the key-value pairs
379func (l logger) With(keysAndValues Fields) Logger {
380 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
381}
382
383// Debug logs a message at level Debug on the standard logger.
384func (l logger) Debug(args ...interface{}) {
385 l.log.Debug(args...)
386}
387
388// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
389func (l logger) Debugln(args ...interface{}) {
390 l.log.Debug(args...)
391}
392
393// Debugw logs a message at level Debug on the standard logger.
394func (l logger) Debugf(format string, args ...interface{}) {
395 l.log.Debugf(format, args...)
396}
397
398// Debugw logs a message with some additional context. The variadic key-value
399// pairs are treated as they are in With.
400func (l logger) Debugw(msg string, keysAndValues Fields) {
401 l.log.Debugw(msg, serializeMap(keysAndValues)...)
402}
403
404// Info logs a message at level Info on the standard logger.
405func (l logger) Info(args ...interface{}) {
406 l.log.Info(args...)
407}
408
409// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
410func (l logger) Infoln(args ...interface{}) {
411 l.log.Info(args...)
412 //msg := fmt.Sprintln(args...)
413 //l.sourced().Info(msg[:len(msg)-1])
414}
415
416// Infof logs a message at level Info on the standard logger.
417func (l logger) Infof(format string, args ...interface{}) {
418 l.log.Infof(format, args...)
419}
420
421// Infow logs a message with some additional context. The variadic key-value
422// pairs are treated as they are in With.
423func (l logger) Infow(msg string, keysAndValues Fields) {
424 l.log.Infow(msg, serializeMap(keysAndValues)...)
425}
426
427// Warn logs a message at level Warn on the standard logger.
428func (l logger) Warn(args ...interface{}) {
429 l.log.Warn(args...)
430}
431
432// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
433func (l logger) Warnln(args ...interface{}) {
434 l.log.Warn(args...)
435}
436
437// Warnf logs a message at level Warn on the standard logger.
438func (l logger) Warnf(format string, args ...interface{}) {
439 l.log.Warnf(format, args...)
440}
441
442// Warnw logs a message with some additional context. The variadic key-value
443// pairs are treated as they are in With.
444func (l logger) Warnw(msg string, keysAndValues Fields) {
445 l.log.Warnw(msg, serializeMap(keysAndValues)...)
446}
447
448// Error logs a message at level Error on the standard logger.
449func (l logger) Error(args ...interface{}) {
450 l.log.Error(args...)
451}
452
453// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
454func (l logger) Errorln(args ...interface{}) {
455 l.log.Error(args...)
456}
457
458// Errorf logs a message at level Error on the standard logger.
459func (l logger) Errorf(format string, args ...interface{}) {
460 l.log.Errorf(format, args...)
461}
462
463// Errorw logs a message with some additional context. The variadic key-value
464// pairs are treated as they are in With.
465func (l logger) Errorw(msg string, keysAndValues Fields) {
466 l.log.Errorw(msg, serializeMap(keysAndValues)...)
467}
468
469// Fatal logs a message at level Fatal on the standard logger.
470func (l logger) Fatal(args ...interface{}) {
471 l.log.Fatal(args...)
472}
473
474// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
475func (l logger) Fatalln(args ...interface{}) {
476 l.log.Fatal(args...)
477}
478
479// Fatalf logs a message at level Fatal on the standard logger.
480func (l logger) Fatalf(format string, args ...interface{}) {
481 l.log.Fatalf(format, args...)
482}
483
484// Fatalw logs a message with some additional context. The variadic key-value
485// pairs are treated as they are in With.
486func (l logger) Fatalw(msg string, keysAndValues Fields) {
487 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
488}
489
490// With returns a logger initialized with the key-value pairs
491func With(keysAndValues Fields) Logger {
khenaidoob9203542018-09-17 22:56:37 -0400492 return logger{log: getPackageLevelLogger().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
khenaidoocfee5f42018-07-19 22:47:38 -0400493}
494
495// Debug logs a message at level Debug on the standard logger.
496func Debug(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400497 getPackageLevelLogger().Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400498}
499
500// Debugln logs a message at level Debug on the standard logger.
501func Debugln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400502 getPackageLevelLogger().Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400503}
504
505// Debugf logs a message at level Debug on the standard logger.
506func Debugf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400507 getPackageLevelLogger().Debugf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400508}
509
510// Debugw logs a message with some additional context. The variadic key-value
511// pairs are treated as they are in With.
512func Debugw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400513 getPackageLevelLogger().Debugw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400514}
515
516// Info logs a message at level Info on the standard logger.
517func Info(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400518 getPackageLevelLogger().Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400519}
520
521// Infoln logs a message at level Info on the standard logger.
522func Infoln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400523 getPackageLevelLogger().Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400524}
525
526// Infof logs a message at level Info on the standard logger.
527func Infof(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400528 getPackageLevelLogger().Infof(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400529}
530
531//Infow logs a message with some additional context. The variadic key-value
532//pairs are treated as they are in With.
533func Infow(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400534 getPackageLevelLogger().Infow(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400535}
536
537// Warn logs a message at level Warn on the standard logger.
538func Warn(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400539 getPackageLevelLogger().Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400540}
541
542// Warnln logs a message at level Warn on the standard logger.
543func Warnln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400544 getPackageLevelLogger().Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400545}
546
547// Warnf logs a message at level Warn on the standard logger.
548func Warnf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400549 getPackageLevelLogger().Warnf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400550}
551
552// Warnw logs a message with some additional context. The variadic key-value
553// pairs are treated as they are in With.
554func Warnw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400555 getPackageLevelLogger().Warnw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400556}
557
558// Error logs a message at level Error on the standard logger.
559func Error(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400560 getPackageLevelLogger().Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400561}
562
563// Errorln logs a message at level Error on the standard logger.
564func Errorln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400565 getPackageLevelLogger().Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400566}
567
568// Errorf logs a message at level Error on the standard logger.
569func Errorf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400570 getPackageLevelLogger().Errorf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400571}
572
573// Errorw logs a message with some additional context. The variadic key-value
574// pairs are treated as they are in With.
575func Errorw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400576 getPackageLevelLogger().Errorw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400577}
578
579// Fatal logs a message at level Fatal on the standard logger.
580func Fatal(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400581 getPackageLevelLogger().Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400582}
583
584// Fatalln logs a message at level Fatal on the standard logger.
585func Fatalln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400586 getPackageLevelLogger().Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400587}
588
589// Fatalf logs a message at level Fatal on the standard logger.
590func Fatalf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400591 getPackageLevelLogger().Fatalf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400592}
593
594// Fatalw logs a message with some additional context. The variadic key-value
595// pairs are treated as they are in With.
596func Fatalw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400597 getPackageLevelLogger().Fatalw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400598}