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