blob: 1e23da1383f155364811541a8e69b953eb6e58bd [file] [log] [blame]
Scott Baker2c1c4822019-10-16 11:02:41 -07001/*
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 */
16
17//Package log provides a structured Logger interface implemented using zap logger. It provides the following capabilities:
18//1. Package level logging - a go package can register itself (AddPackage) and have a logger created for that package.
19//2. Dynamic log level change - for all registered packages (SetAllLogLevel)
20//3. Dynamic log level change - for a given package (SetPackageLogLevel)
21//4. Provides a default logger for unregistered packages
22//5. Allow key-value pairs to be added to a logger(UpdateLogger) or all loggers (UpdateAllLoggers) at run time
23//6. Add to the log output the location where the log was invoked (filename.functionname.linenumber)
24//
25// Using package-level logging (recommended approach). In the examples below, log refers to this log package.
26// 1. In the appropriate package add the following in the init section of the package. The log level can be changed
27// and any number of default fields can be added as well. The log level specifies the lowest log level that will be
28// in the output while the fields will be automatically added to all log printouts.
29//
30// log.AddPackage(mylog.JSON, log.WarnLevel, log.Fields{"anyFieldName": "any value"})
31//
32//2. In the calling package, just invoke any of the publicly available functions of the logger. Here is an example
33// to write an Info log with additional fields:
34//
35//log.Infow("An example", mylog.Fields{"myStringOutput": "output", "myIntOutput": 2})
36//
37//3. To dynamically change the log level, you can use 1)SetLogLevel from inside your package or 2) SetPackageLogLevel
38// from anywhere or 3) SetAllLogLevel from anywhere.
39//
40
41package log
42
43import (
Girish Kumar46d7c3a2020-05-18 12:06:33 +000044 "context"
Scott Baker2c1c4822019-10-16 11:02:41 -070045 "errors"
46 "fmt"
47 zp "go.uber.org/zap"
48 zc "go.uber.org/zap/zapcore"
49 "path"
50 "runtime"
51 "strings"
52)
53
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +000054type LogLevel int8
55
Scott Baker2c1c4822019-10-16 11:02:41 -070056const (
57 // DebugLevel logs a message at debug level
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +000058 DebugLevel = LogLevel(iota)
Scott Baker2c1c4822019-10-16 11:02:41 -070059 // InfoLevel logs a message at info level
60 InfoLevel
61 // WarnLevel logs a message at warning level
62 WarnLevel
63 // ErrorLevel logs a message at error level
64 ErrorLevel
Scott Baker2c1c4822019-10-16 11:02:41 -070065 // FatalLevel logs a message, then calls os.Exit(1).
66 FatalLevel
67)
68
69// CONSOLE formats the log for the console, mostly used during development
70const CONSOLE = "console"
71
72// JSON formats the log using json format, mostly used by an automated logging system consumption
73const JSON = "json"
74
Girish Kumar46d7c3a2020-05-18 12:06:33 +000075// Context Aware Logger represents an abstract logging interface. Any logging implementation used
Scott Baker2c1c4822019-10-16 11:02:41 -070076// will need to abide by this interface
Girish Kumar46d7c3a2020-05-18 12:06:33 +000077type CLogger interface {
78 Debug(context.Context, ...interface{})
79 Debugln(context.Context, ...interface{})
80 Debugf(context.Context, string, ...interface{})
81 Debugw(context.Context, string, Fields)
Scott Baker2c1c4822019-10-16 11:02:41 -070082
Girish Kumar46d7c3a2020-05-18 12:06:33 +000083 Info(context.Context, ...interface{})
84 Infoln(context.Context, ...interface{})
85 Infof(context.Context, string, ...interface{})
86 Infow(context.Context, string, Fields)
Scott Baker2c1c4822019-10-16 11:02:41 -070087
Girish Kumar46d7c3a2020-05-18 12:06:33 +000088 Warn(context.Context, ...interface{})
89 Warnln(context.Context, ...interface{})
90 Warnf(context.Context, string, ...interface{})
91 Warnw(context.Context, string, Fields)
Scott Baker2c1c4822019-10-16 11:02:41 -070092
Girish Kumar46d7c3a2020-05-18 12:06:33 +000093 Error(context.Context, ...interface{})
94 Errorln(context.Context, ...interface{})
95 Errorf(context.Context, string, ...interface{})
96 Errorw(context.Context, string, Fields)
Scott Baker2c1c4822019-10-16 11:02:41 -070097
Girish Kumar46d7c3a2020-05-18 12:06:33 +000098 Fatal(context.Context, ...interface{})
99 Fatalln(context.Context, ...interface{})
100 Fatalf(context.Context, string, ...interface{})
101 Fatalw(context.Context, string, Fields)
Scott Baker2c1c4822019-10-16 11:02:41 -0700102
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000103 With(Fields) CLogger
Scott Baker2c1c4822019-10-16 11:02:41 -0700104
105 // The following are added to be able to use this logger as a gRPC LoggerV2 if needed
106 //
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000107 Warning(context.Context, ...interface{})
108 Warningln(context.Context, ...interface{})
109 Warningf(context.Context, string, ...interface{})
Scott Baker2c1c4822019-10-16 11:02:41 -0700110
111 // V reports whether verbosity level l is at least the requested verbose level.
Scott Bakerd7c25f42020-02-21 08:12:06 -0800112 V(l LogLevel) bool
khenaidoob332f9b2020-01-16 16:25:26 -0500113
114 //Returns the log level of this specific logger
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000115 GetLogLevel() LogLevel
Scott Baker2c1c4822019-10-16 11:02:41 -0700116}
117
118// Fields is used as key-value pairs for structured logging
119type Fields map[string]interface{}
120
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000121var defaultLogger *clogger
Scott Baker2c1c4822019-10-16 11:02:41 -0700122var cfg zp.Config
123
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000124var loggers map[string]*clogger
Scott Baker2c1c4822019-10-16 11:02:41 -0700125var cfgs map[string]zp.Config
126
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000127type clogger struct {
khenaidoob332f9b2020-01-16 16:25:26 -0500128 log *zp.SugaredLogger
129 parent *zp.Logger
130 packageName string
Scott Baker2c1c4822019-10-16 11:02:41 -0700131}
132
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000133func logLevelToAtomicLevel(l LogLevel) zp.AtomicLevel {
Scott Baker2c1c4822019-10-16 11:02:41 -0700134 switch l {
135 case DebugLevel:
136 return zp.NewAtomicLevelAt(zc.DebugLevel)
137 case InfoLevel:
138 return zp.NewAtomicLevelAt(zc.InfoLevel)
139 case WarnLevel:
140 return zp.NewAtomicLevelAt(zc.WarnLevel)
141 case ErrorLevel:
142 return zp.NewAtomicLevelAt(zc.ErrorLevel)
Scott Baker2c1c4822019-10-16 11:02:41 -0700143 case FatalLevel:
144 return zp.NewAtomicLevelAt(zc.FatalLevel)
145 }
146 return zp.NewAtomicLevelAt(zc.ErrorLevel)
147}
148
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000149func logLevelToLevel(l LogLevel) zc.Level {
Scott Baker2c1c4822019-10-16 11:02:41 -0700150 switch l {
151 case DebugLevel:
152 return zc.DebugLevel
153 case InfoLevel:
154 return zc.InfoLevel
155 case WarnLevel:
156 return zc.WarnLevel
157 case ErrorLevel:
158 return zc.ErrorLevel
Scott Baker2c1c4822019-10-16 11:02:41 -0700159 case FatalLevel:
160 return zc.FatalLevel
161 }
162 return zc.ErrorLevel
163}
164
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000165func levelToLogLevel(l zc.Level) LogLevel {
Scott Baker2c1c4822019-10-16 11:02:41 -0700166 switch l {
167 case zc.DebugLevel:
168 return DebugLevel
169 case zc.InfoLevel:
170 return InfoLevel
171 case zc.WarnLevel:
172 return WarnLevel
173 case zc.ErrorLevel:
174 return ErrorLevel
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000175 case zc.FatalLevel:
176 return FatalLevel
177 }
178 return ErrorLevel
179}
180
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000181func StringToLogLevel(l string) (LogLevel, error) {
182 switch strings.ToUpper(l) {
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000183 case "DEBUG":
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000184 return DebugLevel, nil
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000185 case "INFO":
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000186 return InfoLevel, nil
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000187 case "WARN":
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000188 return WarnLevel, nil
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000189 case "ERROR":
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000190 return ErrorLevel, nil
Rohan Agrawal6a99a452020-01-14 07:58:25 +0000191 case "FATAL":
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000192 return FatalLevel, nil
Scott Baker2c1c4822019-10-16 11:02:41 -0700193 }
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000194 return 0, errors.New("Given LogLevel is invalid : " + l)
Scott Baker2c1c4822019-10-16 11:02:41 -0700195}
196
divyadesai8bf96862020-02-07 12:24:26 +0000197func LogLevelToString(l LogLevel) (string, error) {
198 switch l {
199 case DebugLevel:
200 return "DEBUG", nil
201 case InfoLevel:
202 return "INFO", nil
203 case WarnLevel:
204 return "WARN", nil
205 case ErrorLevel:
206 return "ERROR", nil
207 case FatalLevel:
208 return "FATAL", nil
209 }
210 return "", errors.New("Given LogLevel is invalid " + string(l))
211}
212
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000213func getDefaultConfig(outputType string, level LogLevel, defaultFields Fields) zp.Config {
Scott Baker2c1c4822019-10-16 11:02:41 -0700214 return zp.Config{
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000215 Level: logLevelToAtomicLevel(level),
Scott Baker2c1c4822019-10-16 11:02:41 -0700216 Encoding: outputType,
217 Development: true,
218 OutputPaths: []string{"stdout"},
219 ErrorOutputPaths: []string{"stderr"},
220 InitialFields: defaultFields,
221 EncoderConfig: zc.EncoderConfig{
222 LevelKey: "level",
223 MessageKey: "msg",
224 TimeKey: "ts",
Girish Kumarc9b0e712020-02-27 17:50:52 +0000225 CallerKey: "caller",
Scott Baker2c1c4822019-10-16 11:02:41 -0700226 StacktraceKey: "stacktrace",
227 LineEnding: zc.DefaultLineEnding,
228 EncodeLevel: zc.LowercaseLevelEncoder,
229 EncodeTime: zc.ISO8601TimeEncoder,
230 EncodeDuration: zc.SecondsDurationEncoder,
231 EncodeCaller: zc.ShortCallerEncoder,
232 },
233 }
234}
235
Rohan Agrawalee87e642020-04-14 10:22:18 +0000236func ConstructZapConfig(outputType string, level LogLevel, fields Fields) zp.Config {
237 return getDefaultConfig(outputType, level, fields)
238}
239
Scott Baker2c1c4822019-10-16 11:02:41 -0700240// SetLogger needs to be invoked before the logger API can be invoked. This function
241// initialize the default logger (zap's sugaredlogger)
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000242func SetDefaultLogger(outputType string, level LogLevel, defaultFields Fields) (CLogger, error) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700243 // Build a custom config using zap
244 cfg = getDefaultConfig(outputType, level, defaultFields)
245
Girish Kumarc9b0e712020-02-27 17:50:52 +0000246 l, err := cfg.Build(zp.AddCallerSkip(1))
Scott Baker2c1c4822019-10-16 11:02:41 -0700247 if err != nil {
248 return nil, err
249 }
250
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000251 defaultLogger = &clogger{
Scott Baker2c1c4822019-10-16 11:02:41 -0700252 log: l.Sugar(),
253 parent: l,
254 }
255
256 return defaultLogger, nil
257}
258
259// AddPackage registers a package to the log map. Each package gets its own logger which allows
260// its config (loglevel) to be changed dynamically without interacting with the other packages.
261// outputType is JSON, level is the lowest level log to output with this logger and defaultFields is a map of
262// key-value pairs to always add to the output.
263// Note: AddPackage also returns a reference to the actual logger. If a calling package uses this reference directly
264//instead of using the publicly available functions in this log package then a number of functionalities will not
265// be available to it, notably log tracing with filename.functionname.linenumber annotation.
266//
267// pkgNames parameter should be used for testing only as this function detects the caller's package.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000268func RegisterPackage(outputType string, level LogLevel, defaultFields Fields, pkgNames ...string) (CLogger, error) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700269 if cfgs == nil {
270 cfgs = make(map[string]zp.Config)
271 }
272 if loggers == nil {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000273 loggers = make(map[string]*clogger)
Scott Baker2c1c4822019-10-16 11:02:41 -0700274 }
275
276 var pkgName string
277 for _, name := range pkgNames {
278 pkgName = name
279 break
280 }
281 if pkgName == "" {
282 pkgName, _, _, _ = getCallerInfo()
283 }
284
285 if _, exist := loggers[pkgName]; exist {
286 return loggers[pkgName], nil
287 }
288
289 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
290
Girish Kumarc9b0e712020-02-27 17:50:52 +0000291 l, err := cfgs[pkgName].Build(zp.AddCallerSkip(1))
Scott Baker2c1c4822019-10-16 11:02:41 -0700292 if err != nil {
293 return nil, err
294 }
295
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000296 loggers[pkgName] = &clogger{
khenaidoob332f9b2020-01-16 16:25:26 -0500297 log: l.Sugar(),
298 parent: l,
299 packageName: pkgName,
Scott Baker2c1c4822019-10-16 11:02:41 -0700300 }
301 return loggers[pkgName], nil
302}
303
304//UpdateAllLoggers create new loggers for all registered pacakges with the defaultFields.
305func UpdateAllLoggers(defaultFields Fields) error {
306 for pkgName, cfg := range cfgs {
307 for k, v := range defaultFields {
308 if cfg.InitialFields == nil {
309 cfg.InitialFields = make(map[string]interface{})
310 }
311 cfg.InitialFields[k] = v
312 }
Girish Kumarc9b0e712020-02-27 17:50:52 +0000313 l, err := cfg.Build(zp.AddCallerSkip(1))
Scott Baker2c1c4822019-10-16 11:02:41 -0700314 if err != nil {
315 return err
316 }
317
Girish Kumarc9b0e712020-02-27 17:50:52 +0000318 // Update the existing zap logger instance
319 loggers[pkgName].log = l.Sugar()
320 loggers[pkgName].parent = l
Scott Baker2c1c4822019-10-16 11:02:41 -0700321 }
322 return nil
323}
324
325// Return a list of all packages that have individually-configured loggers
326func GetPackageNames() []string {
327 i := 0
328 keys := make([]string, len(loggers))
329 for k := range loggers {
330 keys[i] = k
331 i++
332 }
333 return keys
334}
335
Girish Kumarc9b0e712020-02-27 17:50:52 +0000336// UpdateLogger updates the logger associated with a caller's package with supplied defaultFields
337func UpdateLogger(defaultFields Fields) error {
Scott Baker2c1c4822019-10-16 11:02:41 -0700338 pkgName, _, _, _ := getCallerInfo()
339 if _, exist := loggers[pkgName]; !exist {
Girish Kumarc9b0e712020-02-27 17:50:52 +0000340 return fmt.Errorf("package-%s-not-registered", pkgName)
Scott Baker2c1c4822019-10-16 11:02:41 -0700341 }
342
343 // Build a new logger
344 if _, exist := cfgs[pkgName]; !exist {
Girish Kumarc9b0e712020-02-27 17:50:52 +0000345 return fmt.Errorf("config-%s-not-registered", pkgName)
Scott Baker2c1c4822019-10-16 11:02:41 -0700346 }
347
348 cfg := cfgs[pkgName]
349 for k, v := range defaultFields {
350 if cfg.InitialFields == nil {
351 cfg.InitialFields = make(map[string]interface{})
352 }
353 cfg.InitialFields[k] = v
354 }
Girish Kumarc9b0e712020-02-27 17:50:52 +0000355 l, err := cfg.Build(zp.AddCallerSkip(1))
Scott Baker2c1c4822019-10-16 11:02:41 -0700356 if err != nil {
Girish Kumarc9b0e712020-02-27 17:50:52 +0000357 return err
Scott Baker2c1c4822019-10-16 11:02:41 -0700358 }
359
Girish Kumarc9b0e712020-02-27 17:50:52 +0000360 // Update the existing zap logger instance
361 loggers[pkgName].log = l.Sugar()
362 loggers[pkgName].parent = l
363
364 return nil
Scott Baker2c1c4822019-10-16 11:02:41 -0700365}
366
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000367func setLevel(cfg zp.Config, level LogLevel) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700368 switch level {
369 case DebugLevel:
370 cfg.Level.SetLevel(zc.DebugLevel)
371 case InfoLevel:
372 cfg.Level.SetLevel(zc.InfoLevel)
373 case WarnLevel:
374 cfg.Level.SetLevel(zc.WarnLevel)
375 case ErrorLevel:
376 cfg.Level.SetLevel(zc.ErrorLevel)
Scott Baker2c1c4822019-10-16 11:02:41 -0700377 case FatalLevel:
378 cfg.Level.SetLevel(zc.FatalLevel)
379 default:
380 cfg.Level.SetLevel(zc.ErrorLevel)
381 }
382}
383
384//SetPackageLogLevel dynamically sets the log level of a given package to level. This is typically invoked at an
385// application level during debugging
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000386func SetPackageLogLevel(packageName string, level LogLevel) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700387 // Get proper config
388 if cfg, ok := cfgs[packageName]; ok {
389 setLevel(cfg, level)
390 }
391}
392
393//SetAllLogLevel sets the log level of all registered packages to level
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000394func SetAllLogLevel(level LogLevel) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700395 // Get proper config
396 for _, cfg := range cfgs {
397 setLevel(cfg, level)
398 }
399}
400
401//GetPackageLogLevel returns the current log level of a package.
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000402func GetPackageLogLevel(packageName ...string) (LogLevel, error) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700403 var name string
404 if len(packageName) == 1 {
405 name = packageName[0]
406 } else {
407 name, _, _, _ = getCallerInfo()
408 }
409 if cfg, ok := cfgs[name]; ok {
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000410 return levelToLogLevel(cfg.Level.Level()), nil
Scott Baker2c1c4822019-10-16 11:02:41 -0700411 }
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800412 return 0, fmt.Errorf("unknown-package-%s", name)
Scott Baker2c1c4822019-10-16 11:02:41 -0700413}
414
415//GetDefaultLogLevel gets the log level used for packages that don't have specific loggers
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000416func GetDefaultLogLevel() LogLevel {
417 return levelToLogLevel(cfg.Level.Level())
Scott Baker2c1c4822019-10-16 11:02:41 -0700418}
419
420//SetLogLevel sets the log level for the logger corresponding to the caller's package
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000421func SetLogLevel(level LogLevel) error {
Scott Baker2c1c4822019-10-16 11:02:41 -0700422 pkgName, _, _, _ := getCallerInfo()
423 if _, exist := cfgs[pkgName]; !exist {
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800424 return fmt.Errorf("unregistered-package-%s", pkgName)
Scott Baker2c1c4822019-10-16 11:02:41 -0700425 }
426 cfg := cfgs[pkgName]
427 setLevel(cfg, level)
428 return nil
429}
430
431//SetDefaultLogLevel sets the log level used for packages that don't have specific loggers
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000432func SetDefaultLogLevel(level LogLevel) {
Scott Baker2c1c4822019-10-16 11:02:41 -0700433 setLevel(cfg, level)
434}
435
436// CleanUp flushed any buffered log entries. Applications should take care to call
437// CleanUp before exiting.
438func CleanUp() error {
439 for _, logger := range loggers {
440 if logger != nil {
441 if logger.parent != nil {
442 if err := logger.parent.Sync(); err != nil {
443 return err
444 }
445 }
446 }
447 }
448 if defaultLogger != nil {
449 if defaultLogger.parent != nil {
450 if err := defaultLogger.parent.Sync(); err != nil {
451 return err
452 }
453 }
454 }
455 return nil
456}
457
458func getCallerInfo() (string, string, string, int) {
459 // Since the caller of a log function is one stack frame before (in terms of stack higher level) the log.go
460 // filename, then first look for the last log.go filename and then grab the caller info one level higher.
461 maxLevel := 3
462 skiplevel := 3 // Level with the most empirical success to see the last log.go stack frame.
463 pc := make([]uintptr, maxLevel)
464 n := runtime.Callers(skiplevel, pc)
465 packageName := ""
466 funcName := ""
467 fileName := ""
468 var line int
469 if n == 0 {
470 return packageName, fileName, funcName, line
471 }
472 frames := runtime.CallersFrames(pc[:n])
473 var frame runtime.Frame
474 var foundFrame runtime.Frame
475 more := true
476 for more {
477 frame, more = frames.Next()
478 _, fileName = path.Split(frame.File)
479 if fileName != "log.go" {
480 foundFrame = frame // First frame after log.go in the frame stack
481 break
482 }
483 }
484 parts := strings.Split(foundFrame.Function, ".")
485 pl := len(parts)
486 if pl >= 2 {
487 funcName = parts[pl-1]
488 if parts[pl-2][0] == '(' {
489 packageName = strings.Join(parts[0:pl-2], ".")
490 } else {
491 packageName = strings.Join(parts[0:pl-1], ".")
492 }
493 }
494
495 if strings.HasSuffix(packageName, ".init") {
496 packageName = strings.TrimSuffix(packageName, ".init")
497 }
498
499 if strings.HasSuffix(fileName, ".go") {
500 fileName = strings.TrimSuffix(fileName, ".go")
501 }
502
503 return packageName, fileName, funcName, foundFrame.Line
504}
505
Scott Baker2c1c4822019-10-16 11:02:41 -0700506// With returns a logger initialized with the key-value pairs
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000507func (l clogger) With(keysAndValues Fields) CLogger {
508 return clogger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
Scott Baker2c1c4822019-10-16 11:02:41 -0700509}
510
511// Debug logs a message at level Debug on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000512func (l clogger) Debug(ctx context.Context, args ...interface{}) {
513 l.log.With(ExtractContextAttributes(ctx)...).Debug(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700514}
515
516// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000517func (l clogger) Debugln(ctx context.Context, args ...interface{}) {
518 l.log.With(ExtractContextAttributes(ctx)...).Debug(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700519}
520
521// Debugw logs a message at level Debug on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000522func (l clogger) Debugf(ctx context.Context, format string, args ...interface{}) {
523 l.log.With(ExtractContextAttributes(ctx)...).Debugf(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700524}
525
526// Debugw logs a message with some additional context. The variadic key-value
527// pairs are treated as they are in With.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000528func (l clogger) Debugw(ctx context.Context, msg string, keysAndValues Fields) {
khenaidoob3ec7d52020-04-29 16:52:08 -0400529 if l.V(DebugLevel) {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000530 l.log.With(ExtractContextAttributes(ctx)...).Debugw(msg, serializeMap(keysAndValues)...)
khenaidoob3ec7d52020-04-29 16:52:08 -0400531 }
Scott Baker2c1c4822019-10-16 11:02:41 -0700532}
533
534// Info logs a message at level Info on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000535func (l clogger) Info(ctx context.Context, args ...interface{}) {
536 l.log.With(ExtractContextAttributes(ctx)...).Info(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700537}
538
539// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000540func (l clogger) Infoln(ctx context.Context, args ...interface{}) {
541 l.log.With(ExtractContextAttributes(ctx)...).Info(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700542 //msg := fmt.Sprintln(args...)
543 //l.sourced().Info(msg[:len(msg)-1])
544}
545
546// Infof logs a message at level Info on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000547func (l clogger) Infof(ctx context.Context, format string, args ...interface{}) {
548 l.log.With(ExtractContextAttributes(ctx)...).Infof(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700549}
550
551// Infow logs a message with some additional context. The variadic key-value
552// pairs are treated as they are in With.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000553func (l clogger) Infow(ctx context.Context, msg string, keysAndValues Fields) {
khenaidoob3ec7d52020-04-29 16:52:08 -0400554 if l.V(InfoLevel) {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000555 l.log.With(ExtractContextAttributes(ctx)...).Infow(msg, serializeMap(keysAndValues)...)
khenaidoob3ec7d52020-04-29 16:52:08 -0400556 }
Scott Baker2c1c4822019-10-16 11:02:41 -0700557}
558
559// Warn logs a message at level Warn on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000560func (l clogger) Warn(ctx context.Context, args ...interface{}) {
561 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700562}
563
564// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000565func (l clogger) Warnln(ctx context.Context, args ...interface{}) {
566 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700567}
568
569// Warnf logs a message at level Warn on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000570func (l clogger) Warnf(ctx context.Context, format string, args ...interface{}) {
571 l.log.With(ExtractContextAttributes(ctx)...).Warnf(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700572}
573
574// Warnw logs a message with some additional context. The variadic key-value
575// pairs are treated as they are in With.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000576func (l clogger) Warnw(ctx context.Context, msg string, keysAndValues Fields) {
khenaidoob3ec7d52020-04-29 16:52:08 -0400577 if l.V(WarnLevel) {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000578 l.log.With(ExtractContextAttributes(ctx)...).Warnw(msg, serializeMap(keysAndValues)...)
khenaidoob3ec7d52020-04-29 16:52:08 -0400579 }
Scott Baker2c1c4822019-10-16 11:02:41 -0700580}
581
582// Error logs a message at level Error on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000583func (l clogger) Error(ctx context.Context, args ...interface{}) {
584 l.log.With(ExtractContextAttributes(ctx)...).Error(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700585}
586
587// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000588func (l clogger) Errorln(ctx context.Context, args ...interface{}) {
589 l.log.With(ExtractContextAttributes(ctx)...).Error(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700590}
591
592// Errorf logs a message at level Error on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000593func (l clogger) Errorf(ctx context.Context, format string, args ...interface{}) {
594 l.log.With(ExtractContextAttributes(ctx)...).Errorf(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700595}
596
597// Errorw logs a message with some additional context. The variadic key-value
598// pairs are treated as they are in With.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000599func (l clogger) Errorw(ctx context.Context, msg string, keysAndValues Fields) {
khenaidoob3ec7d52020-04-29 16:52:08 -0400600 if l.V(ErrorLevel) {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000601 l.log.With(ExtractContextAttributes(ctx)...).Errorw(msg, serializeMap(keysAndValues)...)
khenaidoob3ec7d52020-04-29 16:52:08 -0400602 }
Scott Baker2c1c4822019-10-16 11:02:41 -0700603}
604
605// Fatal logs a message at level Fatal on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000606func (l clogger) Fatal(ctx context.Context, args ...interface{}) {
607 l.log.With(ExtractContextAttributes(ctx)...).Fatal(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700608}
609
610// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000611func (l clogger) Fatalln(ctx context.Context, args ...interface{}) {
612 l.log.With(ExtractContextAttributes(ctx)...).Fatal(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700613}
614
615// Fatalf logs a message at level Fatal on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000616func (l clogger) Fatalf(ctx context.Context, format string, args ...interface{}) {
617 l.log.With(ExtractContextAttributes(ctx)...).Fatalf(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700618}
619
620// Fatalw logs a message with some additional context. The variadic key-value
621// pairs are treated as they are in With.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000622func (l clogger) Fatalw(ctx context.Context, msg string, keysAndValues Fields) {
khenaidoob3ec7d52020-04-29 16:52:08 -0400623 if l.V(FatalLevel) {
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000624 l.log.With(ExtractContextAttributes(ctx)...).Fatalw(msg, serializeMap(keysAndValues)...)
khenaidoob3ec7d52020-04-29 16:52:08 -0400625 }
Scott Baker2c1c4822019-10-16 11:02:41 -0700626}
627
628// Warning logs a message at level Warn on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000629func (l clogger) Warning(ctx context.Context, args ...interface{}) {
630 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700631}
632
633// Warningln logs a message at level Warn on the standard logger with a line feed. Default in any case.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000634func (l clogger) Warningln(ctx context.Context, args ...interface{}) {
635 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700636}
637
638// Warningf logs a message at level Warn on the standard logger.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000639func (l clogger) Warningf(ctx context.Context, format string, args ...interface{}) {
640 l.log.With(ExtractContextAttributes(ctx)...).Warnf(format, args...)
Scott Baker2c1c4822019-10-16 11:02:41 -0700641}
642
643// V reports whether verbosity level l is at least the requested verbose level.
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000644func (l clogger) V(level LogLevel) bool {
Scott Bakerd7c25f42020-02-21 08:12:06 -0800645 return l.parent.Core().Enabled(logLevelToLevel(level))
Scott Baker2c1c4822019-10-16 11:02:41 -0700646}
647
khenaidoob332f9b2020-01-16 16:25:26 -0500648// GetLogLevel returns the current level of the logger
Girish Kumar46d7c3a2020-05-18 12:06:33 +0000649func (l clogger) GetLogLevel() LogLevel {
Rohan Agrawal0c62b5d2020-02-04 09:56:21 +0000650 return levelToLogLevel(cfgs[l.packageName].Level.Level())
khenaidoob332f9b2020-01-16 16:25:26 -0500651}