blob: b8d498c820a71bdeb81d258c964ae1bfad6bc63e [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -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 */
16
Girish Kumar935f7af2020-08-18 11:59:42 +000017// 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 (however avoid its usage)
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)
William Kurkianea869482019-04-09 15:16:11 -040024//
25// Using package-level logging (recommended approach). In the examples below, log refers to this log package.
William Kurkianea869482019-04-09 15:16:11 -040026//
Girish Kumar935f7af2020-08-18 11:59:42 +000027// 1. In the appropriate package, add the following in the init section of the package (usually in a common.go file)
28// The log level can be changed and any number of default fields can be added as well. The log level specifies
29// the lowest log level that will be in the output while the fields will be automatically added to all log printouts.
30// However, as voltha components re-initialize the log level of each registered package to default initial loglevel
31// passed as CLI argument, the log level passed in RegisterPackage call effectively has no effect.
William Kurkianea869482019-04-09 15:16:11 -040032//
Girish Kumar935f7af2020-08-18 11:59:42 +000033// var logger log.CLogger
34// func init() {
35// logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{"key1": "value1"})
36// }
William Kurkianea869482019-04-09 15:16:11 -040037//
Girish Kumar935f7af2020-08-18 11:59:42 +000038// 2. In the calling package, use any of the publicly available functions of local package-level logger instance created
39// in previous step. Here is an example to write an Info log with additional fields:
William Kurkianea869482019-04-09 15:16:11 -040040//
Girish Kumar935f7af2020-08-18 11:59:42 +000041// logger.Infow("An example", mylog.Fields{"myStringOutput": "output", "myIntOutput": 2})
William Kurkianea869482019-04-09 15:16:11 -040042//
Girish Kumar935f7af2020-08-18 11:59:42 +000043// 3. To dynamically change the log level, you can use
44// a) SetLogLevel from inside your package or
45// b) SetPackageLogLevel from anywhere or
46// c) SetAllLogLevel from anywhere.
47//
48// Dynamic Loglevel configuration feature also uses SetPackageLogLevel method based on triggers received due to
49// Changes to configured loglevels
William Kurkianea869482019-04-09 15:16:11 -040050
51package log
52
53import (
Girish Gowdra631ef3d2020-06-15 10:45:52 -070054 "context"
William Kurkianea869482019-04-09 15:16:11 -040055 "errors"
56 "fmt"
57 zp "go.uber.org/zap"
58 zc "go.uber.org/zap/zapcore"
59 "path"
60 "runtime"
61 "strings"
62)
63
Rohan Agrawal02f784d2020-02-14 09:34:02 +000064type LogLevel int8
65
William Kurkianea869482019-04-09 15:16:11 -040066const (
67 // DebugLevel logs a message at debug level
Rohan Agrawal02f784d2020-02-14 09:34:02 +000068 DebugLevel = LogLevel(iota)
William Kurkianea869482019-04-09 15:16:11 -040069 // InfoLevel logs a message at info level
70 InfoLevel
71 // WarnLevel logs a message at warning level
72 WarnLevel
73 // ErrorLevel logs a message at error level
74 ErrorLevel
William Kurkianea869482019-04-09 15:16:11 -040075 // FatalLevel logs a message, then calls os.Exit(1).
76 FatalLevel
77)
78
79// CONSOLE formats the log for the console, mostly used during development
80const CONSOLE = "console"
81
82// JSON formats the log using json format, mostly used by an automated logging system consumption
83const JSON = "json"
84
Girish Gowdra631ef3d2020-06-15 10:45:52 -070085// Context Aware Logger represents an abstract logging interface. Any logging implementation used
William Kurkianea869482019-04-09 15:16:11 -040086// will need to abide by this interface
Girish Gowdra631ef3d2020-06-15 10:45:52 -070087type CLogger interface {
88 Debug(context.Context, ...interface{})
89 Debugln(context.Context, ...interface{})
90 Debugf(context.Context, string, ...interface{})
91 Debugw(context.Context, string, Fields)
William Kurkianea869482019-04-09 15:16:11 -040092
Girish Gowdra631ef3d2020-06-15 10:45:52 -070093 Info(context.Context, ...interface{})
94 Infoln(context.Context, ...interface{})
95 Infof(context.Context, string, ...interface{})
96 Infow(context.Context, string, Fields)
William Kurkianea869482019-04-09 15:16:11 -040097
Girish Gowdra631ef3d2020-06-15 10:45:52 -070098 Warn(context.Context, ...interface{})
99 Warnln(context.Context, ...interface{})
100 Warnf(context.Context, string, ...interface{})
101 Warnw(context.Context, string, Fields)
William Kurkianea869482019-04-09 15:16:11 -0400102
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700103 Error(context.Context, ...interface{})
104 Errorln(context.Context, ...interface{})
105 Errorf(context.Context, string, ...interface{})
106 Errorw(context.Context, string, Fields)
William Kurkianea869482019-04-09 15:16:11 -0400107
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700108 Fatal(context.Context, ...interface{})
109 Fatalln(context.Context, ...interface{})
110 Fatalf(context.Context, string, ...interface{})
111 Fatalw(context.Context, string, Fields)
William Kurkianea869482019-04-09 15:16:11 -0400112
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700113 With(Fields) CLogger
William Kurkianea869482019-04-09 15:16:11 -0400114
115 // The following are added to be able to use this logger as a gRPC LoggerV2 if needed
116 //
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700117 Warning(context.Context, ...interface{})
118 Warningln(context.Context, ...interface{})
119 Warningf(context.Context, string, ...interface{})
William Kurkianea869482019-04-09 15:16:11 -0400120
121 // V reports whether verbosity level l is at least the requested verbose level.
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000122 V(l LogLevel) bool
Esin Karamanccb714b2019-11-29 15:02:06 +0000123
124 //Returns the log level of this specific logger
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000125 GetLogLevel() LogLevel
William Kurkianea869482019-04-09 15:16:11 -0400126}
127
128// Fields is used as key-value pairs for structured logging
129type Fields map[string]interface{}
130
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700131var defaultLogger *clogger
William Kurkianea869482019-04-09 15:16:11 -0400132var cfg zp.Config
133
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700134var loggers map[string]*clogger
William Kurkianea869482019-04-09 15:16:11 -0400135var cfgs map[string]zp.Config
136
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700137type clogger struct {
Esin Karamanccb714b2019-11-29 15:02:06 +0000138 log *zp.SugaredLogger
139 parent *zp.Logger
140 packageName string
William Kurkianea869482019-04-09 15:16:11 -0400141}
142
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000143func logLevelToAtomicLevel(l LogLevel) zp.AtomicLevel {
William Kurkianea869482019-04-09 15:16:11 -0400144 switch l {
145 case DebugLevel:
146 return zp.NewAtomicLevelAt(zc.DebugLevel)
147 case InfoLevel:
148 return zp.NewAtomicLevelAt(zc.InfoLevel)
149 case WarnLevel:
150 return zp.NewAtomicLevelAt(zc.WarnLevel)
151 case ErrorLevel:
152 return zp.NewAtomicLevelAt(zc.ErrorLevel)
William Kurkianea869482019-04-09 15:16:11 -0400153 case FatalLevel:
154 return zp.NewAtomicLevelAt(zc.FatalLevel)
155 }
156 return zp.NewAtomicLevelAt(zc.ErrorLevel)
157}
158
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000159func logLevelToLevel(l LogLevel) zc.Level {
William Kurkianea869482019-04-09 15:16:11 -0400160 switch l {
161 case DebugLevel:
162 return zc.DebugLevel
163 case InfoLevel:
164 return zc.InfoLevel
165 case WarnLevel:
166 return zc.WarnLevel
167 case ErrorLevel:
168 return zc.ErrorLevel
William Kurkianea869482019-04-09 15:16:11 -0400169 case FatalLevel:
170 return zc.FatalLevel
171 }
172 return zc.ErrorLevel
173}
174
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000175func levelToLogLevel(l zc.Level) LogLevel {
William Kurkianea869482019-04-09 15:16:11 -0400176 switch l {
177 case zc.DebugLevel:
178 return DebugLevel
179 case zc.InfoLevel:
180 return InfoLevel
181 case zc.WarnLevel:
182 return WarnLevel
183 case zc.ErrorLevel:
184 return ErrorLevel
Esin Karamanccb714b2019-11-29 15:02:06 +0000185 case zc.FatalLevel:
186 return FatalLevel
187 }
188 return ErrorLevel
189}
190
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000191func StringToLogLevel(l string) (LogLevel, error) {
192 switch strings.ToUpper(l) {
Esin Karamanccb714b2019-11-29 15:02:06 +0000193 case "DEBUG":
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000194 return DebugLevel, nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000195 case "INFO":
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000196 return InfoLevel, nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000197 case "WARN":
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000198 return WarnLevel, nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000199 case "ERROR":
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000200 return ErrorLevel, nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000201 case "FATAL":
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000202 return FatalLevel, nil
William Kurkianea869482019-04-09 15:16:11 -0400203 }
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000204 return 0, errors.New("Given LogLevel is invalid : " + l)
William Kurkianea869482019-04-09 15:16:11 -0400205}
206
Scott Bakere701b862020-02-20 16:19:16 -0800207func LogLevelToString(l LogLevel) (string, error) {
208 switch l {
209 case DebugLevel:
210 return "DEBUG", nil
211 case InfoLevel:
212 return "INFO", nil
213 case WarnLevel:
214 return "WARN", nil
215 case ErrorLevel:
216 return "ERROR", nil
217 case FatalLevel:
218 return "FATAL", nil
219 }
220 return "", errors.New("Given LogLevel is invalid " + string(l))
221}
222
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000223func getDefaultConfig(outputType string, level LogLevel, defaultFields Fields) zp.Config {
William Kurkianea869482019-04-09 15:16:11 -0400224 return zp.Config{
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000225 Level: logLevelToAtomicLevel(level),
William Kurkianea869482019-04-09 15:16:11 -0400226 Encoding: outputType,
227 Development: true,
228 OutputPaths: []string{"stdout"},
229 ErrorOutputPaths: []string{"stderr"},
230 InitialFields: defaultFields,
231 EncoderConfig: zc.EncoderConfig{
232 LevelKey: "level",
233 MessageKey: "msg",
234 TimeKey: "ts",
divyadesaid26f6b12020-03-19 06:30:28 +0000235 CallerKey: "caller",
William Kurkianea869482019-04-09 15:16:11 -0400236 StacktraceKey: "stacktrace",
237 LineEnding: zc.DefaultLineEnding,
238 EncodeLevel: zc.LowercaseLevelEncoder,
239 EncodeTime: zc.ISO8601TimeEncoder,
240 EncodeDuration: zc.SecondsDurationEncoder,
241 EncodeCaller: zc.ShortCallerEncoder,
242 },
243 }
244}
245
Scott Bakered4a8e72020-04-17 11:10:20 -0700246func ConstructZapConfig(outputType string, level LogLevel, fields Fields) zp.Config {
247 return getDefaultConfig(outputType, level, fields)
248}
249
William Kurkianea869482019-04-09 15:16:11 -0400250// SetLogger needs to be invoked before the logger API can be invoked. This function
251// initialize the default logger (zap's sugaredlogger)
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700252func SetDefaultLogger(outputType string, level LogLevel, defaultFields Fields) (CLogger, error) {
William Kurkianea869482019-04-09 15:16:11 -0400253 // Build a custom config using zap
254 cfg = getDefaultConfig(outputType, level, defaultFields)
255
divyadesaid26f6b12020-03-19 06:30:28 +0000256 l, err := cfg.Build(zp.AddCallerSkip(1))
William Kurkianea869482019-04-09 15:16:11 -0400257 if err != nil {
258 return nil, err
259 }
260
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700261 defaultLogger = &clogger{
William Kurkianea869482019-04-09 15:16:11 -0400262 log: l.Sugar(),
263 parent: l,
264 }
265
266 return defaultLogger, nil
267}
268
269// AddPackage registers a package to the log map. Each package gets its own logger which allows
270// its config (loglevel) to be changed dynamically without interacting with the other packages.
271// outputType is JSON, level is the lowest level log to output with this logger and defaultFields is a map of
272// key-value pairs to always add to the output.
273// Note: AddPackage also returns a reference to the actual logger. If a calling package uses this reference directly
274//instead of using the publicly available functions in this log package then a number of functionalities will not
275// be available to it, notably log tracing with filename.functionname.linenumber annotation.
276//
277// pkgNames parameter should be used for testing only as this function detects the caller's package.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700278func RegisterPackage(outputType string, level LogLevel, defaultFields Fields, pkgNames ...string) (CLogger, error) {
William Kurkianea869482019-04-09 15:16:11 -0400279 if cfgs == nil {
280 cfgs = make(map[string]zp.Config)
281 }
282 if loggers == nil {
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700283 loggers = make(map[string]*clogger)
William Kurkianea869482019-04-09 15:16:11 -0400284 }
285
286 var pkgName string
287 for _, name := range pkgNames {
288 pkgName = name
289 break
290 }
291 if pkgName == "" {
292 pkgName, _, _, _ = getCallerInfo()
293 }
294
295 if _, exist := loggers[pkgName]; exist {
296 return loggers[pkgName], nil
297 }
298
299 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
300
divyadesaid26f6b12020-03-19 06:30:28 +0000301 l, err := cfgs[pkgName].Build(zp.AddCallerSkip(1))
William Kurkianea869482019-04-09 15:16:11 -0400302 if err != nil {
303 return nil, err
304 }
305
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700306 loggers[pkgName] = &clogger{
Esin Karamanccb714b2019-11-29 15:02:06 +0000307 log: l.Sugar(),
308 parent: l,
309 packageName: pkgName,
William Kurkianea869482019-04-09 15:16:11 -0400310 }
311 return loggers[pkgName], nil
312}
313
314//UpdateAllLoggers create new loggers for all registered pacakges with the defaultFields.
315func UpdateAllLoggers(defaultFields Fields) error {
316 for pkgName, cfg := range cfgs {
317 for k, v := range defaultFields {
318 if cfg.InitialFields == nil {
319 cfg.InitialFields = make(map[string]interface{})
320 }
321 cfg.InitialFields[k] = v
322 }
divyadesaid26f6b12020-03-19 06:30:28 +0000323 l, err := cfg.Build(zp.AddCallerSkip(1))
William Kurkianea869482019-04-09 15:16:11 -0400324 if err != nil {
325 return err
326 }
327
divyadesaid26f6b12020-03-19 06:30:28 +0000328 // Update the existing zap logger instance
329 loggers[pkgName].log = l.Sugar()
330 loggers[pkgName].parent = l
William Kurkianea869482019-04-09 15:16:11 -0400331 }
332 return nil
333}
334
kdarapub26b4502019-10-05 03:02:33 +0530335// Return a list of all packages that have individually-configured loggers
336func GetPackageNames() []string {
337 i := 0
338 keys := make([]string, len(loggers))
339 for k := range loggers {
340 keys[i] = k
341 i++
342 }
343 return keys
344}
345
divyadesaid26f6b12020-03-19 06:30:28 +0000346// UpdateLogger updates the logger associated with a caller's package with supplied defaultFields
347func UpdateLogger(defaultFields Fields) error {
William Kurkianea869482019-04-09 15:16:11 -0400348 pkgName, _, _, _ := getCallerInfo()
349 if _, exist := loggers[pkgName]; !exist {
divyadesaid26f6b12020-03-19 06:30:28 +0000350 return fmt.Errorf("package-%s-not-registered", pkgName)
William Kurkianea869482019-04-09 15:16:11 -0400351 }
352
353 // Build a new logger
354 if _, exist := cfgs[pkgName]; !exist {
divyadesaid26f6b12020-03-19 06:30:28 +0000355 return fmt.Errorf("config-%s-not-registered", pkgName)
William Kurkianea869482019-04-09 15:16:11 -0400356 }
357
358 cfg := cfgs[pkgName]
359 for k, v := range defaultFields {
360 if cfg.InitialFields == nil {
361 cfg.InitialFields = make(map[string]interface{})
362 }
363 cfg.InitialFields[k] = v
364 }
divyadesaid26f6b12020-03-19 06:30:28 +0000365 l, err := cfg.Build(zp.AddCallerSkip(1))
William Kurkianea869482019-04-09 15:16:11 -0400366 if err != nil {
divyadesaid26f6b12020-03-19 06:30:28 +0000367 return err
William Kurkianea869482019-04-09 15:16:11 -0400368 }
369
divyadesaid26f6b12020-03-19 06:30:28 +0000370 // Update the existing zap logger instance
371 loggers[pkgName].log = l.Sugar()
372 loggers[pkgName].parent = l
373
374 return nil
William Kurkianea869482019-04-09 15:16:11 -0400375}
376
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000377func setLevel(cfg zp.Config, level LogLevel) {
William Kurkianea869482019-04-09 15:16:11 -0400378 switch level {
379 case DebugLevel:
380 cfg.Level.SetLevel(zc.DebugLevel)
381 case InfoLevel:
382 cfg.Level.SetLevel(zc.InfoLevel)
383 case WarnLevel:
384 cfg.Level.SetLevel(zc.WarnLevel)
385 case ErrorLevel:
386 cfg.Level.SetLevel(zc.ErrorLevel)
William Kurkianea869482019-04-09 15:16:11 -0400387 case FatalLevel:
388 cfg.Level.SetLevel(zc.FatalLevel)
389 default:
390 cfg.Level.SetLevel(zc.ErrorLevel)
391 }
392}
393
394//SetPackageLogLevel dynamically sets the log level of a given package to level. This is typically invoked at an
395// application level during debugging
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000396func SetPackageLogLevel(packageName string, level LogLevel) {
William Kurkianea869482019-04-09 15:16:11 -0400397 // Get proper config
398 if cfg, ok := cfgs[packageName]; ok {
399 setLevel(cfg, level)
400 }
401}
402
403//SetAllLogLevel sets the log level of all registered packages to level
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000404func SetAllLogLevel(level LogLevel) {
William Kurkianea869482019-04-09 15:16:11 -0400405 // Get proper config
406 for _, cfg := range cfgs {
407 setLevel(cfg, level)
408 }
409}
410
411//GetPackageLogLevel returns the current log level of a package.
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000412func GetPackageLogLevel(packageName ...string) (LogLevel, error) {
Matt Jeanneretcab955f2019-04-10 15:45:57 -0400413 var name string
414 if len(packageName) == 1 {
415 name = packageName[0]
416 } else {
417 name, _, _, _ = getCallerInfo()
418 }
419 if cfg, ok := cfgs[name]; ok {
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000420 return levelToLogLevel(cfg.Level.Level()), nil
William Kurkianea869482019-04-09 15:16:11 -0400421 }
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000422 return 0, fmt.Errorf("unknown-package-%s", name)
William Kurkianea869482019-04-09 15:16:11 -0400423}
424
kdarapub26b4502019-10-05 03:02:33 +0530425//GetDefaultLogLevel gets the log level used for packages that don't have specific loggers
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000426func GetDefaultLogLevel() LogLevel {
427 return levelToLogLevel(cfg.Level.Level())
kdarapub26b4502019-10-05 03:02:33 +0530428}
429
William Kurkianea869482019-04-09 15:16:11 -0400430//SetLogLevel sets the log level for the logger corresponding to the caller's package
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000431func SetLogLevel(level LogLevel) error {
William Kurkianea869482019-04-09 15:16:11 -0400432 pkgName, _, _, _ := getCallerInfo()
433 if _, exist := cfgs[pkgName]; !exist {
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000434 return fmt.Errorf("unregistered-package-%s", pkgName)
William Kurkianea869482019-04-09 15:16:11 -0400435 }
436 cfg := cfgs[pkgName]
437 setLevel(cfg, level)
438 return nil
439}
440
kdarapub26b4502019-10-05 03:02:33 +0530441//SetDefaultLogLevel sets the log level used for packages that don't have specific loggers
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000442func SetDefaultLogLevel(level LogLevel) {
kdarapub26b4502019-10-05 03:02:33 +0530443 setLevel(cfg, level)
444}
445
William Kurkianea869482019-04-09 15:16:11 -0400446// CleanUp flushed any buffered log entries. Applications should take care to call
447// CleanUp before exiting.
448func CleanUp() error {
449 for _, logger := range loggers {
450 if logger != nil {
451 if logger.parent != nil {
452 if err := logger.parent.Sync(); err != nil {
453 return err
454 }
455 }
456 }
457 }
458 if defaultLogger != nil {
459 if defaultLogger.parent != nil {
460 if err := defaultLogger.parent.Sync(); err != nil {
461 return err
462 }
463 }
464 }
465 return nil
466}
467
468func getCallerInfo() (string, string, string, int) {
469 // Since the caller of a log function is one stack frame before (in terms of stack higher level) the log.go
470 // filename, then first look for the last log.go filename and then grab the caller info one level higher.
471 maxLevel := 3
472 skiplevel := 3 // Level with the most empirical success to see the last log.go stack frame.
473 pc := make([]uintptr, maxLevel)
474 n := runtime.Callers(skiplevel, pc)
475 packageName := ""
476 funcName := ""
477 fileName := ""
478 var line int
479 if n == 0 {
480 return packageName, fileName, funcName, line
481 }
482 frames := runtime.CallersFrames(pc[:n])
483 var frame runtime.Frame
484 var foundFrame runtime.Frame
485 more := true
486 for more {
487 frame, more = frames.Next()
488 _, fileName = path.Split(frame.File)
489 if fileName != "log.go" {
490 foundFrame = frame // First frame after log.go in the frame stack
491 break
492 }
493 }
494 parts := strings.Split(foundFrame.Function, ".")
495 pl := len(parts)
496 if pl >= 2 {
497 funcName = parts[pl-1]
498 if parts[pl-2][0] == '(' {
499 packageName = strings.Join(parts[0:pl-2], ".")
500 } else {
501 packageName = strings.Join(parts[0:pl-1], ".")
502 }
503 }
504
505 if strings.HasSuffix(packageName, ".init") {
506 packageName = strings.TrimSuffix(packageName, ".init")
507 }
508
509 if strings.HasSuffix(fileName, ".go") {
510 fileName = strings.TrimSuffix(fileName, ".go")
511 }
512
513 return packageName, fileName, funcName, foundFrame.Line
514}
515
William Kurkianea869482019-04-09 15:16:11 -0400516// With returns a logger initialized with the key-value pairs
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700517func (l clogger) With(keysAndValues Fields) CLogger {
518 return clogger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
William Kurkianea869482019-04-09 15:16:11 -0400519}
520
521// Debug logs a message at level Debug on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700522func (l clogger) Debug(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000523 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Debug(args...)
William Kurkianea869482019-04-09 15:16:11 -0400524}
525
526// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700527func (l clogger) Debugln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000528 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Debug(args...)
William Kurkianea869482019-04-09 15:16:11 -0400529}
530
531// Debugw logs a message at level Debug on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700532func (l clogger) Debugf(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000533 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Debugf(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400534}
535
536// Debugw logs a message with some additional context. The variadic key-value
537// pairs are treated as they are in With.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700538func (l clogger) Debugw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharmacc656962020-04-14 14:26:11 +0000539 if l.V(DebugLevel) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000540 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Debugw(msg, serializeMap(keysAndValues)...)
Neha Sharmacc656962020-04-14 14:26:11 +0000541 }
William Kurkianea869482019-04-09 15:16:11 -0400542}
543
544// Info logs a message at level Info on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700545func (l clogger) Info(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000546 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Info(args...)
William Kurkianea869482019-04-09 15:16:11 -0400547}
548
549// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700550func (l clogger) Infoln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000551 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Info(args...)
William Kurkianea869482019-04-09 15:16:11 -0400552 //msg := fmt.Sprintln(args...)
553 //l.sourced().Info(msg[:len(msg)-1])
554}
555
556// Infof logs a message at level Info on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700557func (l clogger) Infof(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000558 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Infof(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400559}
560
561// Infow logs a message with some additional context. The variadic key-value
562// pairs are treated as they are in With.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700563func (l clogger) Infow(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharmacc656962020-04-14 14:26:11 +0000564 if l.V(InfoLevel) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000565 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Infow(msg, serializeMap(keysAndValues)...)
Neha Sharmacc656962020-04-14 14:26:11 +0000566 }
William Kurkianea869482019-04-09 15:16:11 -0400567}
568
569// Warn logs a message at level Warn on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700570func (l clogger) Warn(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000571 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warn(args...)
William Kurkianea869482019-04-09 15:16:11 -0400572}
573
574// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700575func (l clogger) Warnln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000576 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warn(args...)
William Kurkianea869482019-04-09 15:16:11 -0400577}
578
579// Warnf logs a message at level Warn on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700580func (l clogger) Warnf(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000581 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warnf(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400582}
583
584// Warnw logs a message with some additional context. The variadic key-value
585// pairs are treated as they are in With.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700586func (l clogger) Warnw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharmacc656962020-04-14 14:26:11 +0000587 if l.V(WarnLevel) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000588 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warnw(msg, serializeMap(keysAndValues)...)
Neha Sharmacc656962020-04-14 14:26:11 +0000589 }
William Kurkianea869482019-04-09 15:16:11 -0400590}
591
592// Error logs a message at level Error on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700593func (l clogger) Error(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000594 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Error(args...)
William Kurkianea869482019-04-09 15:16:11 -0400595}
596
597// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700598func (l clogger) Errorln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000599 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Error(args...)
William Kurkianea869482019-04-09 15:16:11 -0400600}
601
602// Errorf logs a message at level Error on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700603func (l clogger) Errorf(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000604 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Errorf(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400605}
606
607// Errorw logs a message with some additional context. The variadic key-value
608// pairs are treated as they are in With.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700609func (l clogger) Errorw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharmacc656962020-04-14 14:26:11 +0000610 if l.V(ErrorLevel) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000611 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Errorw(msg, serializeMap(keysAndValues)...)
Neha Sharmacc656962020-04-14 14:26:11 +0000612 }
William Kurkianea869482019-04-09 15:16:11 -0400613}
614
615// Fatal logs a message at level Fatal on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700616func (l clogger) Fatal(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000617 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Fatal(args...)
William Kurkianea869482019-04-09 15:16:11 -0400618}
619
620// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700621func (l clogger) Fatalln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000622 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Fatal(args...)
William Kurkianea869482019-04-09 15:16:11 -0400623}
624
625// Fatalf logs a message at level Fatal on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700626func (l clogger) Fatalf(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000627 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Fatalf(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400628}
629
630// Fatalw logs a message with some additional context. The variadic key-value
631// pairs are treated as they are in With.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700632func (l clogger) Fatalw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharmacc656962020-04-14 14:26:11 +0000633 if l.V(FatalLevel) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000634 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Fatalw(msg, serializeMap(keysAndValues)...)
Neha Sharmacc656962020-04-14 14:26:11 +0000635 }
William Kurkianea869482019-04-09 15:16:11 -0400636}
637
638// Warning logs a message at level Warn on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700639func (l clogger) Warning(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000640 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warn(args...)
William Kurkianea869482019-04-09 15:16:11 -0400641}
642
643// Warningln logs a message at level Warn on the standard logger with a line feed. Default in any case.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700644func (l clogger) Warningln(ctx context.Context, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000645 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warn(args...)
William Kurkianea869482019-04-09 15:16:11 -0400646}
647
648// Warningf logs a message at level Warn on the standard logger.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700649func (l clogger) Warningf(ctx context.Context, format string, args ...interface{}) {
Girish Kumar935f7af2020-08-18 11:59:42 +0000650 l.log.With(GetGlobalLFM().ExtractContextAttributes(ctx)...).Warnf(format, args...)
William Kurkianea869482019-04-09 15:16:11 -0400651}
652
653// V reports whether verbosity level l is at least the requested verbose level.
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700654func (l clogger) V(level LogLevel) bool {
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000655 return l.parent.Core().Enabled(logLevelToLevel(level))
William Kurkianea869482019-04-09 15:16:11 -0400656}
657
Esin Karamanccb714b2019-11-29 15:02:06 +0000658// GetLogLevel returns the current level of the logger
Girish Gowdra631ef3d2020-06-15 10:45:52 -0700659func (l clogger) GetLogLevel() LogLevel {
Rohan Agrawal02f784d2020-02-14 09:34:02 +0000660 return levelToLogLevel(cfgs[l.packageName].Level.Level())
Esin Karamanccb714b2019-11-29 15:02:06 +0000661}