blob: 1e23da1383f155364811541a8e69b953eb6e58bd [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 */
khenaidoo7da372d2018-09-21 16:03:09 -040016
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
khenaidoocfee5f42018-07-19 22:47:38 -040041package log
42
43import (
khenaidooc6c7bda2020-06-17 17:20:18 -040044 "context"
khenaidoo7da372d2018-09-21 16:03:09 -040045 "errors"
khenaidoo5c11af72018-07-20 17:21:05 -040046 "fmt"
khenaidoocfee5f42018-07-19 22:47:38 -040047 zp "go.uber.org/zap"
48 zc "go.uber.org/zap/zapcore"
khenaidoob9203542018-09-17 22:56:37 -040049 "path"
khenaidoocfee5f42018-07-19 22:47:38 -040050 "runtime"
51 "strings"
khenaidoocfee5f42018-07-19 22:47:38 -040052)
53
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +000054type LogLevel int8
55
khenaidoocfee5f42018-07-19 22:47:38 -040056const (
57 // DebugLevel logs a message at debug level
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +000058 DebugLevel = LogLevel(iota)
khenaidoocfee5f42018-07-19 22:47:38 -040059 // 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
khenaidoocfee5f42018-07-19 22:47:38 -040065 // 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"
khenaidoo5c11af72018-07-20 17:21:05 -040071
khenaidoocfee5f42018-07-19 22:47:38 -040072// JSON formats the log using json format, mostly used by an automated logging system consumption
73const JSON = "json"
74
khenaidooc6c7bda2020-06-17 17:20:18 -040075// Context Aware Logger represents an abstract logging interface. Any logging implementation used
khenaidoocfee5f42018-07-19 22:47:38 -040076// will need to abide by this interface
khenaidooc6c7bda2020-06-17 17:20:18 -040077type CLogger interface {
78 Debug(context.Context, ...interface{})
79 Debugln(context.Context, ...interface{})
80 Debugf(context.Context, string, ...interface{})
81 Debugw(context.Context, string, Fields)
khenaidoocfee5f42018-07-19 22:47:38 -040082
khenaidooc6c7bda2020-06-17 17:20:18 -040083 Info(context.Context, ...interface{})
84 Infoln(context.Context, ...interface{})
85 Infof(context.Context, string, ...interface{})
86 Infow(context.Context, string, Fields)
khenaidoocfee5f42018-07-19 22:47:38 -040087
khenaidooc6c7bda2020-06-17 17:20:18 -040088 Warn(context.Context, ...interface{})
89 Warnln(context.Context, ...interface{})
90 Warnf(context.Context, string, ...interface{})
91 Warnw(context.Context, string, Fields)
khenaidoocfee5f42018-07-19 22:47:38 -040092
khenaidooc6c7bda2020-06-17 17:20:18 -040093 Error(context.Context, ...interface{})
94 Errorln(context.Context, ...interface{})
95 Errorf(context.Context, string, ...interface{})
96 Errorw(context.Context, string, Fields)
khenaidoocfee5f42018-07-19 22:47:38 -040097
khenaidooc6c7bda2020-06-17 17:20:18 -040098 Fatal(context.Context, ...interface{})
99 Fatalln(context.Context, ...interface{})
100 Fatalf(context.Context, string, ...interface{})
101 Fatalw(context.Context, string, Fields)
khenaidoocfee5f42018-07-19 22:47:38 -0400102
khenaidooc6c7bda2020-06-17 17:20:18 -0400103 With(Fields) CLogger
khenaidoo7da372d2018-09-21 16:03:09 -0400104
105 // The following are added to be able to use this logger as a gRPC LoggerV2 if needed
106 //
khenaidooc6c7bda2020-06-17 17:20:18 -0400107 Warning(context.Context, ...interface{})
108 Warningln(context.Context, ...interface{})
109 Warningf(context.Context, string, ...interface{})
khenaidoo7da372d2018-09-21 16:03:09 -0400110
111 // V reports whether verbosity level l is at least the requested verbose level.
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000112 V(l LogLevel) bool
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800113
114 //Returns the log level of this specific logger
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000115 GetLogLevel() LogLevel
khenaidoocfee5f42018-07-19 22:47:38 -0400116}
117
khenaidoo7da372d2018-09-21 16:03:09 -0400118// Fields is used as key-value pairs for structured logging
khenaidoocfee5f42018-07-19 22:47:38 -0400119type Fields map[string]interface{}
120
khenaidooc6c7bda2020-06-17 17:20:18 -0400121var defaultLogger *clogger
khenaidoob9203542018-09-17 22:56:37 -0400122var cfg zp.Config
123
khenaidooc6c7bda2020-06-17 17:20:18 -0400124var loggers map[string]*clogger
khenaidoob9203542018-09-17 22:56:37 -0400125var cfgs map[string]zp.Config
khenaidoocfee5f42018-07-19 22:47:38 -0400126
khenaidooc6c7bda2020-06-17 17:20:18 -0400127type clogger struct {
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800128 log *zp.SugaredLogger
129 parent *zp.Logger
130 packageName string
khenaidoocfee5f42018-07-19 22:47:38 -0400131}
132
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000133func logLevelToAtomicLevel(l LogLevel) zp.AtomicLevel {
khenaidoocfee5f42018-07-19 22:47:38 -0400134 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)
khenaidoocfee5f42018-07-19 22:47:38 -0400143 case FatalLevel:
144 return zp.NewAtomicLevelAt(zc.FatalLevel)
145 }
146 return zp.NewAtomicLevelAt(zc.ErrorLevel)
147}
148
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000149func logLevelToLevel(l LogLevel) zc.Level {
khenaidoo7da372d2018-09-21 16:03:09 -0400150 switch l {
151 case DebugLevel:
152 return zc.DebugLevel
153 case InfoLevel:
khenaidoo6f2fbe32019-01-18 16:16:50 -0500154 return zc.InfoLevel
khenaidoo7da372d2018-09-21 16:03:09 -0400155 case WarnLevel:
156 return zc.WarnLevel
157 case ErrorLevel:
158 return zc.ErrorLevel
khenaidoo7da372d2018-09-21 16:03:09 -0400159 case FatalLevel:
160 return zc.FatalLevel
161 }
162 return zc.ErrorLevel
163}
164
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000165func levelToLogLevel(l zc.Level) LogLevel {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500166 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
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800175 case zc.FatalLevel:
176 return FatalLevel
177 }
178 return ErrorLevel
179}
180
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000181func StringToLogLevel(l string) (LogLevel, error) {
182 switch strings.ToUpper(l) {
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800183 case "DEBUG":
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000184 return DebugLevel, nil
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800185 case "INFO":
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000186 return InfoLevel, nil
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800187 case "WARN":
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000188 return WarnLevel, nil
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800189 case "ERROR":
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000190 return ErrorLevel, nil
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800191 case "FATAL":
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000192 return FatalLevel, nil
khenaidoo6f2fbe32019-01-18 16:16:50 -0500193 }
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000194 return 0, errors.New("Given LogLevel is invalid : " + l)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500195}
196
Scott Baker0e78ba22020-02-24 17:58:47 -0800197func 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 Agrawal7f72f0c2020-01-14 12:05:51 +0000213func getDefaultConfig(outputType string, level LogLevel, defaultFields Fields) zp.Config {
khenaidoocfee5f42018-07-19 22:47:38 -0400214 return zp.Config{
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000215 Level: logLevelToAtomicLevel(level),
khenaidoocfee5f42018-07-19 22:47:38 -0400216 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",
Scott Bakerb9635992020-03-11 21:11:28 -0700225 CallerKey: "caller",
khenaidoocfee5f42018-07-19 22:47:38 -0400226 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
Scott Baker504b4802020-04-17 10:12:20 -0700236func ConstructZapConfig(outputType string, level LogLevel, fields Fields) zp.Config {
237 return getDefaultConfig(outputType, level, fields)
238}
239
khenaidoocfee5f42018-07-19 22:47:38 -0400240// SetLogger needs to be invoked before the logger API can be invoked. This function
241// initialize the default logger (zap's sugaredlogger)
khenaidooc6c7bda2020-06-17 17:20:18 -0400242func SetDefaultLogger(outputType string, level LogLevel, defaultFields Fields) (CLogger, error) {
khenaidoocfee5f42018-07-19 22:47:38 -0400243 // Build a custom config using zap
khenaidood4d922e2018-08-03 22:35:16 -0400244 cfg = getDefaultConfig(outputType, level, defaultFields)
khenaidoocfee5f42018-07-19 22:47:38 -0400245
Scott Bakerb9635992020-03-11 21:11:28 -0700246 l, err := cfg.Build(zp.AddCallerSkip(1))
khenaidoocfee5f42018-07-19 22:47:38 -0400247 if err != nil {
248 return nil, err
249 }
250
khenaidooc6c7bda2020-06-17 17:20:18 -0400251 defaultLogger = &clogger{
khenaidoocfee5f42018-07-19 22:47:38 -0400252 log: l.Sugar(),
253 parent: l,
254 }
255
256 return defaultLogger, nil
257}
258
khenaidoo7da372d2018-09-21 16:03:09 -0400259// 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//
khenaidoo6f2fbe32019-01-18 16:16:50 -0500267// pkgNames parameter should be used for testing only as this function detects the caller's package.
khenaidooc6c7bda2020-06-17 17:20:18 -0400268func RegisterPackage(outputType string, level LogLevel, defaultFields Fields, pkgNames ...string) (CLogger, error) {
khenaidoob9203542018-09-17 22:56:37 -0400269 if cfgs == nil {
270 cfgs = make(map[string]zp.Config)
271 }
272 if loggers == nil {
khenaidooc6c7bda2020-06-17 17:20:18 -0400273 loggers = make(map[string]*clogger)
khenaidoob9203542018-09-17 22:56:37 -0400274 }
khenaidoo6f2fbe32019-01-18 16:16:50 -0500275
276 var pkgName string
277 for _, name := range pkgNames {
278 pkgName = name
279 break
280 }
281 if pkgName == "" {
282 pkgName, _, _, _ = getCallerInfo()
283 }
khenaidoob9203542018-09-17 22:56:37 -0400284
khenaidoo7da372d2018-09-21 16:03:09 -0400285 if _, exist := loggers[pkgName]; exist {
286 return loggers[pkgName], nil
khenaidoob9203542018-09-17 22:56:37 -0400287 }
khenaidoo7da372d2018-09-21 16:03:09 -0400288
khenaidoob9203542018-09-17 22:56:37 -0400289 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
290
Scott Bakerb9635992020-03-11 21:11:28 -0700291 l, err := cfgs[pkgName].Build(zp.AddCallerSkip(1))
khenaidoob9203542018-09-17 22:56:37 -0400292 if err != nil {
khenaidoo7da372d2018-09-21 16:03:09 -0400293 return nil, err
khenaidoob9203542018-09-17 22:56:37 -0400294 }
295
khenaidooc6c7bda2020-06-17 17:20:18 -0400296 loggers[pkgName] = &clogger{
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800297 log: l.Sugar(),
298 parent: l,
299 packageName: pkgName,
khenaidoob9203542018-09-17 22:56:37 -0400300 }
khenaidoo7da372d2018-09-21 16:03:09 -0400301 return loggers[pkgName], nil
khenaidoob9203542018-09-17 22:56:37 -0400302}
303
khenaidoo7da372d2018-09-21 16:03:09 -0400304//UpdateAllLoggers create new loggers for all registered pacakges with the defaultFields.
khenaidoob9203542018-09-17 22:56:37 -0400305func 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 }
Scott Bakerb9635992020-03-11 21:11:28 -0700313 l, err := cfg.Build(zp.AddCallerSkip(1))
khenaidoob9203542018-09-17 22:56:37 -0400314 if err != nil {
315 return err
316 }
317
Scott Bakerb9635992020-03-11 21:11:28 -0700318 // Update the existing zap logger instance
319 loggers[pkgName].log = l.Sugar()
320 loggers[pkgName].parent = l
khenaidoob9203542018-09-17 22:56:37 -0400321 }
322 return nil
323}
324
Scott Baker5f401472019-08-22 08:32:26 -0700325// 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
Scott Bakerb9635992020-03-11 21:11:28 -0700336// UpdateLogger updates the logger associated with a caller's package with supplied defaultFields
337func UpdateLogger(defaultFields Fields) error {
khenaidoo7da372d2018-09-21 16:03:09 -0400338 pkgName, _, _, _ := getCallerInfo()
339 if _, exist := loggers[pkgName]; !exist {
Scott Bakerb9635992020-03-11 21:11:28 -0700340 return fmt.Errorf("package-%s-not-registered", pkgName)
khenaidoo7da372d2018-09-21 16:03:09 -0400341 }
khenaidoob9203542018-09-17 22:56:37 -0400342
khenaidoo7da372d2018-09-21 16:03:09 -0400343 // Build a new logger
344 if _, exist := cfgs[pkgName]; !exist {
Scott Bakerb9635992020-03-11 21:11:28 -0700345 return fmt.Errorf("config-%s-not-registered", pkgName)
khenaidoo7da372d2018-09-21 16:03:09 -0400346 }
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 }
Scott Bakerb9635992020-03-11 21:11:28 -0700355 l, err := cfg.Build(zp.AddCallerSkip(1))
khenaidoo7da372d2018-09-21 16:03:09 -0400356 if err != nil {
Scott Bakerb9635992020-03-11 21:11:28 -0700357 return err
khenaidoo7da372d2018-09-21 16:03:09 -0400358 }
359
Scott Bakerb9635992020-03-11 21:11:28 -0700360 // Update the existing zap logger instance
361 loggers[pkgName].log = l.Sugar()
362 loggers[pkgName].parent = l
363
364 return nil
khenaidoo7da372d2018-09-21 16:03:09 -0400365}
366
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000367func setLevel(cfg zp.Config, level LogLevel) {
khenaidoo7da372d2018-09-21 16:03:09 -0400368 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)
khenaidoo7da372d2018-09-21 16:03:09 -0400377 case FatalLevel:
378 cfg.Level.SetLevel(zc.FatalLevel)
379 default:
380 cfg.Level.SetLevel(zc.ErrorLevel)
381 }
khenaidoo6f2fbe32019-01-18 16:16:50 -0500382}
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 Agrawal7f72f0c2020-01-14 12:05:51 +0000386func SetPackageLogLevel(packageName string, level LogLevel) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500387 // 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 Agrawal7f72f0c2020-01-14 12:05:51 +0000394func SetAllLogLevel(level LogLevel) {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500395 // 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 Agrawal7f72f0c2020-01-14 12:05:51 +0000402func GetPackageLogLevel(packageName ...string) (LogLevel, error) {
khenaidoo910204f2019-04-08 17:56:40 -0400403 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 Agrawal7f72f0c2020-01-14 12:05:51 +0000410 return levelToLogLevel(cfg.Level.Level()), nil
khenaidoo6f2fbe32019-01-18 16:16:50 -0500411 }
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000412 return 0, fmt.Errorf("unknown-package-%s", name)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500413}
414
Scott Baker5f401472019-08-22 08:32:26 -0700415//GetDefaultLogLevel gets the log level used for packages that don't have specific loggers
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000416func GetDefaultLogLevel() LogLevel {
417 return levelToLogLevel(cfg.Level.Level())
Scott Baker5f401472019-08-22 08:32:26 -0700418}
419
khenaidoo6f2fbe32019-01-18 16:16:50 -0500420//SetLogLevel sets the log level for the logger corresponding to the caller's package
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000421func SetLogLevel(level LogLevel) error {
khenaidoo6f2fbe32019-01-18 16:16:50 -0500422 pkgName, _, _, _ := getCallerInfo()
423 if _, exist := cfgs[pkgName]; !exist {
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000424 return fmt.Errorf("unregistered-package-%s", pkgName)
khenaidoo6f2fbe32019-01-18 16:16:50 -0500425 }
426 cfg := cfgs[pkgName]
427 setLevel(cfg, level)
khenaidoo7da372d2018-09-21 16:03:09 -0400428 return nil
429}
430
Scott Baker5f401472019-08-22 08:32:26 -0700431//SetDefaultLogLevel sets the log level used for packages that don't have specific loggers
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000432func SetDefaultLogLevel(level LogLevel) {
Scott Baker5f401472019-08-22 08:32:26 -0700433 setLevel(cfg, level)
434}
435
khenaidoocfee5f42018-07-19 22:47:38 -0400436// CleanUp flushed any buffered log entries. Applications should take care to call
437// CleanUp before exiting.
438func CleanUp() error {
khenaidoob9203542018-09-17 22:56:37 -0400439 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 }
khenaidoocfee5f42018-07-19 22:47:38 -0400448 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
khenaidoo7da372d2018-09-21 16:03:09 -0400458func getCallerInfo() (string, string, string, int) {
khenaidoo2c6f1672018-09-20 23:14:41 -0400459 // 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
khenaidoo7da372d2018-09-21 16:03:09 -0400462 skiplevel := 3 // Level with the most empirical success to see the last log.go stack frame.
khenaidoo2c6f1672018-09-20 23:14:41 -0400463 pc := make([]uintptr, maxLevel)
464 n := runtime.Callers(skiplevel, pc)
khenaidoob9203542018-09-17 22:56:37 -0400465 packageName := ""
khenaidoo2c6f1672018-09-20 23:14:41 -0400466 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 }
khenaidoocfee5f42018-07-19 22:47:38 -0400493 }
494
khenaidoo2c6f1672018-09-20 23:14:41 -0400495 if strings.HasSuffix(packageName, ".init") {
khenaidoo7da372d2018-09-21 16:03:09 -0400496 packageName = strings.TrimSuffix(packageName, ".init")
khenaidoob9203542018-09-17 22:56:37 -0400497 }
498
499 if strings.HasSuffix(fileName, ".go") {
khenaidoo7da372d2018-09-21 16:03:09 -0400500 fileName = strings.TrimSuffix(fileName, ".go")
khenaidoob9203542018-09-17 22:56:37 -0400501 }
khenaidoo2c6f1672018-09-20 23:14:41 -0400502
503 return packageName, fileName, funcName, foundFrame.Line
khenaidoob9203542018-09-17 22:56:37 -0400504}
505
khenaidoocfee5f42018-07-19 22:47:38 -0400506// With returns a logger initialized with the key-value pairs
khenaidooc6c7bda2020-06-17 17:20:18 -0400507func (l clogger) With(keysAndValues Fields) CLogger {
508 return clogger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
khenaidoocfee5f42018-07-19 22:47:38 -0400509}
510
511// Debug logs a message at level Debug on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400512func (l clogger) Debug(ctx context.Context, args ...interface{}) {
513 l.log.With(ExtractContextAttributes(ctx)...).Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400514}
515
516// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400517func (l clogger) Debugln(ctx context.Context, args ...interface{}) {
518 l.log.With(ExtractContextAttributes(ctx)...).Debug(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400519}
520
521// Debugw logs a message at level Debug on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400522func (l clogger) Debugf(ctx context.Context, format string, args ...interface{}) {
523 l.log.With(ExtractContextAttributes(ctx)...).Debugf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400524}
525
526// Debugw logs a message with some additional context. The variadic key-value
527// pairs are treated as they are in With.
khenaidooc6c7bda2020-06-17 17:20:18 -0400528func (l clogger) Debugw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000529 if l.V(DebugLevel) {
khenaidooc6c7bda2020-06-17 17:20:18 -0400530 l.log.With(ExtractContextAttributes(ctx)...).Debugw(msg, serializeMap(keysAndValues)...)
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000531 }
khenaidoocfee5f42018-07-19 22:47:38 -0400532}
533
534// Info logs a message at level Info on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400535func (l clogger) Info(ctx context.Context, args ...interface{}) {
536 l.log.With(ExtractContextAttributes(ctx)...).Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400537}
538
539// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400540func (l clogger) Infoln(ctx context.Context, args ...interface{}) {
541 l.log.With(ExtractContextAttributes(ctx)...).Info(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400542 //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.
khenaidooc6c7bda2020-06-17 17:20:18 -0400547func (l clogger) Infof(ctx context.Context, format string, args ...interface{}) {
548 l.log.With(ExtractContextAttributes(ctx)...).Infof(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400549}
550
551// Infow logs a message with some additional context. The variadic key-value
552// pairs are treated as they are in With.
khenaidooc6c7bda2020-06-17 17:20:18 -0400553func (l clogger) Infow(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000554 if l.V(InfoLevel) {
khenaidooc6c7bda2020-06-17 17:20:18 -0400555 l.log.With(ExtractContextAttributes(ctx)...).Infow(msg, serializeMap(keysAndValues)...)
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000556 }
khenaidoocfee5f42018-07-19 22:47:38 -0400557}
558
559// Warn logs a message at level Warn on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400560func (l clogger) Warn(ctx context.Context, args ...interface{}) {
561 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400562}
563
564// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400565func (l clogger) Warnln(ctx context.Context, args ...interface{}) {
566 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400567}
568
569// Warnf logs a message at level Warn on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400570func (l clogger) Warnf(ctx context.Context, format string, args ...interface{}) {
571 l.log.With(ExtractContextAttributes(ctx)...).Warnf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400572}
573
574// Warnw logs a message with some additional context. The variadic key-value
575// pairs are treated as they are in With.
khenaidooc6c7bda2020-06-17 17:20:18 -0400576func (l clogger) Warnw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000577 if l.V(WarnLevel) {
khenaidooc6c7bda2020-06-17 17:20:18 -0400578 l.log.With(ExtractContextAttributes(ctx)...).Warnw(msg, serializeMap(keysAndValues)...)
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000579 }
khenaidoocfee5f42018-07-19 22:47:38 -0400580}
581
582// Error logs a message at level Error on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400583func (l clogger) Error(ctx context.Context, args ...interface{}) {
584 l.log.With(ExtractContextAttributes(ctx)...).Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400585}
586
587// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400588func (l clogger) Errorln(ctx context.Context, args ...interface{}) {
589 l.log.With(ExtractContextAttributes(ctx)...).Error(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400590}
591
592// Errorf logs a message at level Error on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400593func (l clogger) Errorf(ctx context.Context, format string, args ...interface{}) {
594 l.log.With(ExtractContextAttributes(ctx)...).Errorf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400595}
596
597// Errorw logs a message with some additional context. The variadic key-value
598// pairs are treated as they are in With.
khenaidooc6c7bda2020-06-17 17:20:18 -0400599func (l clogger) Errorw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000600 if l.V(ErrorLevel) {
khenaidooc6c7bda2020-06-17 17:20:18 -0400601 l.log.With(ExtractContextAttributes(ctx)...).Errorw(msg, serializeMap(keysAndValues)...)
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000602 }
khenaidoocfee5f42018-07-19 22:47:38 -0400603}
604
605// Fatal logs a message at level Fatal on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400606func (l clogger) Fatal(ctx context.Context, args ...interface{}) {
607 l.log.With(ExtractContextAttributes(ctx)...).Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400608}
609
610// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400611func (l clogger) Fatalln(ctx context.Context, args ...interface{}) {
612 l.log.With(ExtractContextAttributes(ctx)...).Fatal(args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400613}
614
615// Fatalf logs a message at level Fatal on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400616func (l clogger) Fatalf(ctx context.Context, format string, args ...interface{}) {
617 l.log.With(ExtractContextAttributes(ctx)...).Fatalf(format, args...)
khenaidoocfee5f42018-07-19 22:47:38 -0400618}
619
620// Fatalw logs a message with some additional context. The variadic key-value
621// pairs are treated as they are in With.
khenaidooc6c7bda2020-06-17 17:20:18 -0400622func (l clogger) Fatalw(ctx context.Context, msg string, keysAndValues Fields) {
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000623 if l.V(FatalLevel) {
khenaidooc6c7bda2020-06-17 17:20:18 -0400624 l.log.With(ExtractContextAttributes(ctx)...).Fatalw(msg, serializeMap(keysAndValues)...)
Neha Sharma7d6f3a92020-04-14 15:26:22 +0000625 }
khenaidoocfee5f42018-07-19 22:47:38 -0400626}
627
khenaidoo7da372d2018-09-21 16:03:09 -0400628// Warning logs a message at level Warn on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400629func (l clogger) Warning(ctx context.Context, args ...interface{}) {
630 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
khenaidoo7da372d2018-09-21 16:03:09 -0400631}
632
633// Warningln logs a message at level Warn on the standard logger with a line feed. Default in any case.
khenaidooc6c7bda2020-06-17 17:20:18 -0400634func (l clogger) Warningln(ctx context.Context, args ...interface{}) {
635 l.log.With(ExtractContextAttributes(ctx)...).Warn(args...)
khenaidoo7da372d2018-09-21 16:03:09 -0400636}
637
638// Warningf logs a message at level Warn on the standard logger.
khenaidooc6c7bda2020-06-17 17:20:18 -0400639func (l clogger) Warningf(ctx context.Context, format string, args ...interface{}) {
640 l.log.With(ExtractContextAttributes(ctx)...).Warnf(format, args...)
khenaidoo7da372d2018-09-21 16:03:09 -0400641}
642
643// V reports whether verbosity level l is at least the requested verbose level.
khenaidooc6c7bda2020-06-17 17:20:18 -0400644func (l clogger) V(level LogLevel) bool {
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000645 return l.parent.Core().Enabled(logLevelToLevel(level))
khenaidoo7da372d2018-09-21 16:03:09 -0400646}
647
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800648// GetLogLevel returns the current level of the logger
khenaidooc6c7bda2020-06-17 17:20:18 -0400649func (l clogger) GetLogLevel() LogLevel {
Rohan Agrawal7f72f0c2020-01-14 12:05:51 +0000650 return levelToLogLevel(cfgs[l.packageName].Level.Level())
serkant.uluderya2ae470f2020-01-21 11:13:09 -0800651}