blob: 7f43e87dd18def99b7e3c6ed9b76610fa397b8a0 [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 -0400152
153func AddPackage(outputType string, level int, defaultFields Fields) error {
154 if cfgs == nil {
155 cfgs = make(map[string]zp.Config)
156 }
157 if loggers == nil {
158 loggers = make(map[string]*logger)
159 }
160 pkgName, _, _, _ := getCallerInfo()
161
162 if _, exist := cfgs[pkgName]; exist {
163 return nil
164 }
165 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
166
167 l, err := cfgs[pkgName].Build()
168 if err != nil {
169 return err
170 }
171
172 loggers[pkgName] = &logger{
173 log: l.Sugar(),
174 parent: l,
175 }
176 return nil
177}
178
179func UpdateAllLoggers(defaultFields Fields) error {
180 for pkgName, cfg := range cfgs {
181 for k, v := range defaultFields {
182 if cfg.InitialFields == nil {
183 cfg.InitialFields = make(map[string]interface{})
184 }
185 cfg.InitialFields[k] = v
186 }
187 l, err := cfg.Build()
188 if err != nil {
189 return err
190 }
191
192 loggers[pkgName] = &logger{
193 log: l.Sugar(),
194 parent: l,
195 }
196 }
197 return nil
198}
199
khenaidoob9203542018-09-17 22:56:37 -0400200
201func SetPackageLogLevel(packageName string, level int) {
202 // Get proper config
203 if cfg, ok := cfgs[packageName]; ok {
204 switch level {
205 case DebugLevel:
206 cfg.Level.SetLevel(zc.DebugLevel)
207 case InfoLevel:
208 cfg.Level.SetLevel(zc.InfoLevel)
209 case WarnLevel:
210 cfg.Level.SetLevel(zc.WarnLevel)
211 case ErrorLevel:
212 cfg.Level.SetLevel(zc.ErrorLevel)
213 case PanicLevel:
214 cfg.Level.SetLevel(zc.PanicLevel)
215 case FatalLevel:
216 cfg.Level.SetLevel(zc.FatalLevel)
217 default:
218 cfg.Level.SetLevel(zc.ErrorLevel)
219 }
khenaidood4d922e2018-08-03 22:35:16 -0400220 }
221}
222
khenaidoo2c6f1672018-09-20 23:14:41 -0400223func SetAllLogLevel(level int) {
224 // Get proper config
225 for _, cfg := range cfgs{
226 switch level {
227 case DebugLevel:
228 cfg.Level.SetLevel(zc.DebugLevel)
229 case InfoLevel:
230 cfg.Level.SetLevel(zc.InfoLevel)
231 case WarnLevel:
232 cfg.Level.SetLevel(zc.WarnLevel)
233 case ErrorLevel:
234 cfg.Level.SetLevel(zc.ErrorLevel)
235 case PanicLevel:
236 cfg.Level.SetLevel(zc.PanicLevel)
237 case FatalLevel:
238 cfg.Level.SetLevel(zc.FatalLevel)
239 default:
240 cfg.Level.SetLevel(zc.ErrorLevel)
241 }
242 }
243}
244
khenaidoocfee5f42018-07-19 22:47:38 -0400245// CleanUp flushed any buffered log entries. Applications should take care to call
246// CleanUp before exiting.
247func CleanUp() error {
khenaidoob9203542018-09-17 22:56:37 -0400248 for _, logger := range loggers {
249 if logger != nil {
250 if logger.parent != nil {
251 if err := logger.parent.Sync(); err != nil {
252 return err
253 }
254 }
255 }
256 }
khenaidoocfee5f42018-07-19 22:47:38 -0400257 if defaultLogger != nil {
258 if defaultLogger.parent != nil {
259 if err := defaultLogger.parent.Sync(); err != nil {
260 return err
261 }
262 }
263 }
264 return nil
265}
266
khenaidoo2c6f1672018-09-20 23:14:41 -0400267func getCallerInfo() (string, string, string, int){
268 // Since the caller of a log function is one stack frame before (in terms of stack higher level) the log.go
269 // filename, then first look for the last log.go filename and then grab the caller info one level higher.
270 maxLevel := 3
271 skiplevel := 3 // Level with the most empirical success to see the last log.go stack frame.
272 pc := make([]uintptr, maxLevel)
273 n := runtime.Callers(skiplevel, pc)
khenaidoob9203542018-09-17 22:56:37 -0400274 packageName := ""
khenaidoo2c6f1672018-09-20 23:14:41 -0400275 funcName := ""
276 fileName := ""
277 var line int
278 if n == 0 {
279 return packageName, fileName, funcName, line
280 }
281 frames := runtime.CallersFrames(pc[:n])
282 var frame runtime.Frame
283 var foundFrame runtime.Frame
284 more := true
285 for more {
286 frame, more = frames.Next()
287 _, fileName = path.Split(frame.File)
288 if fileName != "log.go" {
289 foundFrame = frame // First frame after log.go in the frame stack
290 break
291 }
292 }
293 parts := strings.Split(foundFrame.Function, ".")
294 pl := len(parts)
295 if pl >= 2 {
296 funcName = parts[pl-1]
297 if parts[pl-2][0] == '(' {
298 packageName = strings.Join(parts[0:pl-2], ".")
299 } else {
300 packageName = strings.Join(parts[0:pl-1], ".")
301 }
khenaidoocfee5f42018-07-19 22:47:38 -0400302 }
303
khenaidoo2c6f1672018-09-20 23:14:41 -0400304 if strings.HasSuffix(packageName, ".init") {
305 packageName= strings.TrimSuffix(packageName, ".init")
khenaidoob9203542018-09-17 22:56:37 -0400306 }
307
308 if strings.HasSuffix(fileName, ".go") {
khenaidoo2c6f1672018-09-20 23:14:41 -0400309 fileName= strings.TrimSuffix(fileName, ".go")
khenaidoob9203542018-09-17 22:56:37 -0400310 }
khenaidoo2c6f1672018-09-20 23:14:41 -0400311
312 return packageName, fileName, funcName, foundFrame.Line
khenaidoob9203542018-09-17 22:56:37 -0400313}
314
khenaidoo2c6f1672018-09-20 23:14:41 -0400315
khenaidoob9203542018-09-17 22:56:37 -0400316func getPackageLevelLogger() *zp.SugaredLogger {
317 pkgName, fileName, funcName, line := getCallerInfo()
318 if _, exist := loggers[pkgName]; exist {
319 return loggers[pkgName].log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
320 }
321 return defaultLogger.log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
322}
khenaidoocfee5f42018-07-19 22:47:38 -0400323
324func serializeMap(fields Fields) []interface{} {
325 data := make([]interface{}, len(fields)*2)
326 i := 0
327 for k, v := range fields {
328 data[i] = k
329 data[i+1] = v
330 i = i + 2
331 }
332 return data
333}
334
335// With returns a logger initialized with the key-value pairs
336func (l logger) With(keysAndValues Fields) Logger {
337 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
338}
339
340// Debug logs a message at level Debug on the standard logger.
341func (l logger) Debug(args ...interface{}) {
342 l.log.Debug(args...)
343}
344
345// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
346func (l logger) Debugln(args ...interface{}) {
347 l.log.Debug(args...)
348}
349
350// Debugw logs a message at level Debug on the standard logger.
351func (l logger) Debugf(format string, args ...interface{}) {
352 l.log.Debugf(format, args...)
353}
354
355// Debugw logs a message with some additional context. The variadic key-value
356// pairs are treated as they are in With.
357func (l logger) Debugw(msg string, keysAndValues Fields) {
358 l.log.Debugw(msg, serializeMap(keysAndValues)...)
359}
360
361// Info logs a message at level Info on the standard logger.
362func (l logger) Info(args ...interface{}) {
363 l.log.Info(args...)
364}
365
366// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
367func (l logger) Infoln(args ...interface{}) {
368 l.log.Info(args...)
369 //msg := fmt.Sprintln(args...)
370 //l.sourced().Info(msg[:len(msg)-1])
371}
372
373// Infof logs a message at level Info on the standard logger.
374func (l logger) Infof(format string, args ...interface{}) {
375 l.log.Infof(format, args...)
376}
377
378// Infow logs a message with some additional context. The variadic key-value
379// pairs are treated as they are in With.
380func (l logger) Infow(msg string, keysAndValues Fields) {
381 l.log.Infow(msg, serializeMap(keysAndValues)...)
382}
383
384// Warn logs a message at level Warn on the standard logger.
385func (l logger) Warn(args ...interface{}) {
386 l.log.Warn(args...)
387}
388
389// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
390func (l logger) Warnln(args ...interface{}) {
391 l.log.Warn(args...)
392}
393
394// Warnf logs a message at level Warn on the standard logger.
395func (l logger) Warnf(format string, args ...interface{}) {
396 l.log.Warnf(format, args...)
397}
398
399// Warnw logs a message with some additional context. The variadic key-value
400// pairs are treated as they are in With.
401func (l logger) Warnw(msg string, keysAndValues Fields) {
402 l.log.Warnw(msg, serializeMap(keysAndValues)...)
403}
404
405// Error logs a message at level Error on the standard logger.
406func (l logger) Error(args ...interface{}) {
407 l.log.Error(args...)
408}
409
410// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
411func (l logger) Errorln(args ...interface{}) {
412 l.log.Error(args...)
413}
414
415// Errorf logs a message at level Error on the standard logger.
416func (l logger) Errorf(format string, args ...interface{}) {
417 l.log.Errorf(format, args...)
418}
419
420// Errorw logs a message with some additional context. The variadic key-value
421// pairs are treated as they are in With.
422func (l logger) Errorw(msg string, keysAndValues Fields) {
423 l.log.Errorw(msg, serializeMap(keysAndValues)...)
424}
425
426// Fatal logs a message at level Fatal on the standard logger.
427func (l logger) Fatal(args ...interface{}) {
428 l.log.Fatal(args...)
429}
430
431// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
432func (l logger) Fatalln(args ...interface{}) {
433 l.log.Fatal(args...)
434}
435
436// Fatalf logs a message at level Fatal on the standard logger.
437func (l logger) Fatalf(format string, args ...interface{}) {
438 l.log.Fatalf(format, args...)
439}
440
441// Fatalw logs a message with some additional context. The variadic key-value
442// pairs are treated as they are in With.
443func (l logger) Fatalw(msg string, keysAndValues Fields) {
444 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
445}
446
447// With returns a logger initialized with the key-value pairs
448func With(keysAndValues Fields) Logger {
khenaidoob9203542018-09-17 22:56:37 -0400449 return logger{log: getPackageLevelLogger().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
khenaidoocfee5f42018-07-19 22:47:38 -0400450}
451
452// Debug logs a message at level Debug on the standard logger.
453func Debug(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400454 getPackageLevelLogger().Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400455}
456
457// Debugln logs a message at level Debug on the standard logger.
458func Debugln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400459 getPackageLevelLogger().Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400460}
461
462// Debugf logs a message at level Debug on the standard logger.
463func Debugf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400464 getPackageLevelLogger().Debugf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400465}
466
467// Debugw logs a message with some additional context. The variadic key-value
468// pairs are treated as they are in With.
469func Debugw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400470 getPackageLevelLogger().Debugw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400471}
472
473// Info logs a message at level Info on the standard logger.
474func Info(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400475 getPackageLevelLogger().Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400476}
477
478// Infoln logs a message at level Info on the standard logger.
479func Infoln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400480 getPackageLevelLogger().Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400481}
482
483// Infof logs a message at level Info on the standard logger.
484func Infof(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400485 getPackageLevelLogger().Infof(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400486}
487
488//Infow logs a message with some additional context. The variadic key-value
489//pairs are treated as they are in With.
490func Infow(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400491 getPackageLevelLogger().Infow(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400492}
493
494// Warn logs a message at level Warn on the standard logger.
495func Warn(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400496 getPackageLevelLogger().Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400497}
498
499// Warnln logs a message at level Warn on the standard logger.
500func Warnln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400501 getPackageLevelLogger().Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400502}
503
504// Warnf logs a message at level Warn on the standard logger.
505func Warnf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400506 getPackageLevelLogger().Warnf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400507}
508
509// Warnw logs a message with some additional context. The variadic key-value
510// pairs are treated as they are in With.
511func Warnw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400512 getPackageLevelLogger().Warnw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400513}
514
515// Error logs a message at level Error on the standard logger.
516func Error(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400517 getPackageLevelLogger().Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400518}
519
520// Errorln logs a message at level Error on the standard logger.
521func Errorln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400522 getPackageLevelLogger().Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400523}
524
525// Errorf logs a message at level Error on the standard logger.
526func Errorf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400527 getPackageLevelLogger().Errorf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400528}
529
530// Errorw logs a message with some additional context. The variadic key-value
531// pairs are treated as they are in With.
532func Errorw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400533 getPackageLevelLogger().Errorw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400534}
535
536// Fatal logs a message at level Fatal on the standard logger.
537func Fatal(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400538 getPackageLevelLogger().Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400539}
540
541// Fatalln logs a message at level Fatal on the standard logger.
542func Fatalln(args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400543 getPackageLevelLogger().Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400544}
545
546// Fatalf logs a message at level Fatal on the standard logger.
547func Fatalf(format string, args ...interface{}) {
khenaidoob9203542018-09-17 22:56:37 -0400548 getPackageLevelLogger().Fatalf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400549}
550
551// Fatalw logs a message with some additional context. The variadic key-value
552// pairs are treated as they are in With.
553func Fatalw(msg string, keysAndValues Fields) {
khenaidoob9203542018-09-17 22:56:37 -0400554 getPackageLevelLogger().Fatalw(msg, serializeMap(keysAndValues)...)
khenaidoocfee5f42018-07-19 22:47:38 -0400555}