blob: 16fed7457794a353b1daffe41d50d5282fed9bc0 [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
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 (
44 "errors"
45 "fmt"
46 zp "go.uber.org/zap"
47 zc "go.uber.org/zap/zapcore"
48 "path"
49 "runtime"
50 "strings"
51)
52
53const (
54 // DebugLevel logs a message at debug level
55 DebugLevel = iota
56 // InfoLevel logs a message at info level
57 InfoLevel
58 // WarnLevel logs a message at warning level
59 WarnLevel
60 // ErrorLevel logs a message at error level
61 ErrorLevel
62 // PanicLevel logs a message, then panics.
63 PanicLevel
64 // FatalLevel logs a message, then calls os.Exit(1).
65 FatalLevel
66)
67
68// CONSOLE formats the log for the console, mostly used during development
69const CONSOLE = "console"
70
71// JSON formats the log using json format, mostly used by an automated logging system consumption
72const JSON = "json"
73
74// Logger represents an abstract logging interface. Any logging implementation used
75// will need to abide by this interface
76type Logger interface {
77 Debug(...interface{})
78 Debugln(...interface{})
79 Debugf(string, ...interface{})
80 Debugw(string, Fields)
81
82 Info(...interface{})
83 Infoln(...interface{})
84 Infof(string, ...interface{})
85 Infow(string, Fields)
86
87 Warn(...interface{})
88 Warnln(...interface{})
89 Warnf(string, ...interface{})
90 Warnw(string, Fields)
91
92 Error(...interface{})
93 Errorln(...interface{})
94 Errorf(string, ...interface{})
95 Errorw(string, Fields)
96
97 Fatal(...interface{})
98 Fatalln(...interface{})
99 Fatalf(string, ...interface{})
100 Fatalw(string, Fields)
101
102 With(Fields) Logger
103
104 // The following are added to be able to use this logger as a gRPC LoggerV2 if needed
105 //
106 Warning(...interface{})
107 Warningln(...interface{})
108 Warningf(string, ...interface{})
109
110 // V reports whether verbosity level l is at least the requested verbose level.
111 V(l int) bool
112}
113
114// Fields is used as key-value pairs for structured logging
115type Fields map[string]interface{}
116
117var defaultLogger *logger
118var cfg zp.Config
119
120var loggers map[string]*logger
121var cfgs map[string]zp.Config
122
123type logger struct {
124 log *zp.SugaredLogger
125 parent *zp.Logger
126}
127
128func intToAtomicLevel(l int) zp.AtomicLevel {
129 switch l {
130 case DebugLevel:
131 return zp.NewAtomicLevelAt(zc.DebugLevel)
132 case InfoLevel:
133 return zp.NewAtomicLevelAt(zc.InfoLevel)
134 case WarnLevel:
135 return zp.NewAtomicLevelAt(zc.WarnLevel)
136 case ErrorLevel:
137 return zp.NewAtomicLevelAt(zc.ErrorLevel)
138 case PanicLevel:
139 return zp.NewAtomicLevelAt(zc.PanicLevel)
140 case FatalLevel:
141 return zp.NewAtomicLevelAt(zc.FatalLevel)
142 }
143 return zp.NewAtomicLevelAt(zc.ErrorLevel)
144}
145
146func intToLevel(l int) zc.Level {
147 switch l {
148 case DebugLevel:
149 return zc.DebugLevel
150 case InfoLevel:
151 return zc.InfoLevel
152 case WarnLevel:
153 return zc.WarnLevel
154 case ErrorLevel:
155 return zc.ErrorLevel
156 case PanicLevel:
157 return zc.PanicLevel
158 case FatalLevel:
159 return zc.FatalLevel
160 }
161 return zc.ErrorLevel
162}
163
164func levelToInt(l zc.Level) int {
165 switch l {
166 case zc.DebugLevel:
167 return DebugLevel
168 case zc.InfoLevel:
169 return InfoLevel
170 case zc.WarnLevel:
171 return WarnLevel
172 case zc.ErrorLevel:
173 return ErrorLevel
174 case zc.PanicLevel:
175 return PanicLevel
176 case FatalLevel:
177 return FatalLevel
178 }
179 return ErrorLevel
180}
181
182
183func getDefaultConfig(outputType string, level int, defaultFields Fields) zp.Config {
184 return zp.Config{
185 Level: intToAtomicLevel(level),
186 Encoding: outputType,
187 Development: true,
188 OutputPaths: []string{"stdout"},
189 ErrorOutputPaths: []string{"stderr"},
190 InitialFields: defaultFields,
191 EncoderConfig: zc.EncoderConfig{
192 LevelKey: "level",
193 MessageKey: "msg",
194 TimeKey: "ts",
195 StacktraceKey: "stacktrace",
196 LineEnding: zc.DefaultLineEnding,
197 EncodeLevel: zc.LowercaseLevelEncoder,
198 EncodeTime: zc.ISO8601TimeEncoder,
199 EncodeDuration: zc.SecondsDurationEncoder,
200 EncodeCaller: zc.ShortCallerEncoder,
201 },
202 }
203}
204
205// SetLogger needs to be invoked before the logger API can be invoked. This function
206// initialize the default logger (zap's sugaredlogger)
207func SetDefaultLogger(outputType string, level int, defaultFields Fields) (Logger, error) {
208 // Build a custom config using zap
209 cfg = getDefaultConfig(outputType, level, defaultFields)
210
211 l, err := cfg.Build()
212 if err != nil {
213 return nil, err
214 }
215
216 defaultLogger = &logger{
217 log: l.Sugar(),
218 parent: l,
219 }
220
221 return defaultLogger, nil
222}
223
224// AddPackage registers a package to the log map. Each package gets its own logger which allows
225// its config (loglevel) to be changed dynamically without interacting with the other packages.
226// outputType is JSON, level is the lowest level log to output with this logger and defaultFields is a map of
227// key-value pairs to always add to the output.
228// Note: AddPackage also returns a reference to the actual logger. If a calling package uses this reference directly
229//instead of using the publicly available functions in this log package then a number of functionalities will not
230// be available to it, notably log tracing with filename.functionname.linenumber annotation.
231//
232// pkgNames parameter should be used for testing only as this function detects the caller's package.
233func AddPackage(outputType string, level int, defaultFields Fields, pkgNames ...string) (Logger, error) {
234 if cfgs == nil {
235 cfgs = make(map[string]zp.Config)
236 }
237 if loggers == nil {
238 loggers = make(map[string]*logger)
239 }
240
241 var pkgName string
242 for _, name := range pkgNames {
243 pkgName = name
244 break
245 }
246 if pkgName == "" {
247 pkgName, _, _, _ = getCallerInfo()
248 }
249
250 if _, exist := loggers[pkgName]; exist {
251 return loggers[pkgName], nil
252 }
253
254 cfgs[pkgName] = getDefaultConfig(outputType, level, defaultFields)
255
256 l, err := cfgs[pkgName].Build()
257 if err != nil {
258 return nil, err
259 }
260
261 loggers[pkgName] = &logger{
262 log: l.Sugar(),
263 parent: l,
264 }
265 return loggers[pkgName], nil
266}
267
268//UpdateAllLoggers create new loggers for all registered pacakges with the defaultFields.
269func UpdateAllLoggers(defaultFields Fields) error {
270 for pkgName, cfg := range cfgs {
271 for k, v := range defaultFields {
272 if cfg.InitialFields == nil {
273 cfg.InitialFields = make(map[string]interface{})
274 }
275 cfg.InitialFields[k] = v
276 }
277 l, err := cfg.Build()
278 if err != nil {
279 return err
280 }
281
282 loggers[pkgName] = &logger{
283 log: l.Sugar(),
284 parent: l,
285 }
286 }
287 return nil
288}
289
290// UpdateLogger deletes the logger associated with a caller's package and creates a new logger with the
291// defaultFields. If a calling package is holding on to a Logger reference obtained from AddPackage invocation, then
292// that package needs to invoke UpdateLogger if it needs to make changes to the default fields and obtain a new logger
293// reference
294func UpdateLogger(defaultFields Fields) (Logger, error) {
295 pkgName, _, _, _ := getCallerInfo()
296 if _, exist := loggers[pkgName]; !exist {
297 return nil, errors.New(fmt.Sprintf("package-%s-not-registered", pkgName))
298 }
299
300 // Build a new logger
301 if _, exist := cfgs[pkgName]; !exist {
302 return nil, errors.New(fmt.Sprintf("config-%s-not-registered", pkgName))
303 }
304
305 cfg := cfgs[pkgName]
306 for k, v := range defaultFields {
307 if cfg.InitialFields == nil {
308 cfg.InitialFields = make(map[string]interface{})
309 }
310 cfg.InitialFields[k] = v
311 }
312 l, err := cfg.Build()
313 if err != nil {
314 return nil, err
315 }
316
317 // Set the logger
318 loggers[pkgName] = &logger{
319 log: l.Sugar(),
320 parent: l,
321 }
322 return loggers[pkgName], nil
323}
324
325func setLevel(cfg zp.Config, level int) {
326 switch level {
327 case DebugLevel:
328 cfg.Level.SetLevel(zc.DebugLevel)
329 case InfoLevel:
330 cfg.Level.SetLevel(zc.InfoLevel)
331 case WarnLevel:
332 cfg.Level.SetLevel(zc.WarnLevel)
333 case ErrorLevel:
334 cfg.Level.SetLevel(zc.ErrorLevel)
335 case PanicLevel:
336 cfg.Level.SetLevel(zc.PanicLevel)
337 case FatalLevel:
338 cfg.Level.SetLevel(zc.FatalLevel)
339 default:
340 cfg.Level.SetLevel(zc.ErrorLevel)
341 }
342}
343
344//SetPackageLogLevel dynamically sets the log level of a given package to level. This is typically invoked at an
345// application level during debugging
346func SetPackageLogLevel(packageName string, level int) {
347 // Get proper config
348 if cfg, ok := cfgs[packageName]; ok {
349 setLevel(cfg, level)
350 }
351}
352
353//SetAllLogLevel sets the log level of all registered packages to level
354func SetAllLogLevel(level int) {
355 // Get proper config
356 for _, cfg := range cfgs {
357 setLevel(cfg, level)
358 }
359}
360
361//GetPackageLogLevel returns the current log level of a package.
Matt Jeanneretcab955f2019-04-10 15:45:57 -0400362func GetPackageLogLevel(packageName ...string) (int, error) {
363 var name string
364 if len(packageName) == 1 {
365 name = packageName[0]
366 } else {
367 name, _, _, _ = getCallerInfo()
368 }
369 if cfg, ok := cfgs[name]; ok {
William Kurkianea869482019-04-09 15:16:11 -0400370 return levelToInt(cfg.Level.Level()), nil
371 }
Matt Jeanneretcab955f2019-04-10 15:45:57 -0400372 return 0, errors.New(fmt.Sprintf("unknown-package-%s", name))
William Kurkianea869482019-04-09 15:16:11 -0400373}
374
375//SetLogLevel sets the log level for the logger corresponding to the caller's package
376func SetLogLevel(level int) error {
377 pkgName, _, _, _ := getCallerInfo()
378 if _, exist := cfgs[pkgName]; !exist {
379 return errors.New(fmt.Sprintf("unregistered-package-%s", pkgName))
380 }
381 cfg := cfgs[pkgName]
382 setLevel(cfg, level)
383 return nil
384}
385
386// CleanUp flushed any buffered log entries. Applications should take care to call
387// CleanUp before exiting.
388func CleanUp() error {
389 for _, logger := range loggers {
390 if logger != nil {
391 if logger.parent != nil {
392 if err := logger.parent.Sync(); err != nil {
393 return err
394 }
395 }
396 }
397 }
398 if defaultLogger != nil {
399 if defaultLogger.parent != nil {
400 if err := defaultLogger.parent.Sync(); err != nil {
401 return err
402 }
403 }
404 }
405 return nil
406}
407
408func getCallerInfo() (string, string, string, int) {
409 // Since the caller of a log function is one stack frame before (in terms of stack higher level) the log.go
410 // filename, then first look for the last log.go filename and then grab the caller info one level higher.
411 maxLevel := 3
412 skiplevel := 3 // Level with the most empirical success to see the last log.go stack frame.
413 pc := make([]uintptr, maxLevel)
414 n := runtime.Callers(skiplevel, pc)
415 packageName := ""
416 funcName := ""
417 fileName := ""
418 var line int
419 if n == 0 {
420 return packageName, fileName, funcName, line
421 }
422 frames := runtime.CallersFrames(pc[:n])
423 var frame runtime.Frame
424 var foundFrame runtime.Frame
425 more := true
426 for more {
427 frame, more = frames.Next()
428 _, fileName = path.Split(frame.File)
429 if fileName != "log.go" {
430 foundFrame = frame // First frame after log.go in the frame stack
431 break
432 }
433 }
434 parts := strings.Split(foundFrame.Function, ".")
435 pl := len(parts)
436 if pl >= 2 {
437 funcName = parts[pl-1]
438 if parts[pl-2][0] == '(' {
439 packageName = strings.Join(parts[0:pl-2], ".")
440 } else {
441 packageName = strings.Join(parts[0:pl-1], ".")
442 }
443 }
444
445 if strings.HasSuffix(packageName, ".init") {
446 packageName = strings.TrimSuffix(packageName, ".init")
447 }
448
449 if strings.HasSuffix(fileName, ".go") {
450 fileName = strings.TrimSuffix(fileName, ".go")
451 }
452
453 return packageName, fileName, funcName, foundFrame.Line
454}
455
456func getPackageLevelSugaredLogger() *zp.SugaredLogger {
457 pkgName, fileName, funcName, line := getCallerInfo()
458 if _, exist := loggers[pkgName]; exist {
459 return loggers[pkgName].log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
460 }
461 return defaultLogger.log.With("caller", fmt.Sprintf("%s.%s:%d", fileName, funcName, line))
462}
463
464func getPackageLevelLogger() Logger {
465 pkgName, _, _, _ := getCallerInfo()
466 if _, exist := loggers[pkgName]; exist {
467 return loggers[pkgName]
468 }
469 return defaultLogger
470}
471
472func serializeMap(fields Fields) []interface{} {
473 data := make([]interface{}, len(fields)*2)
474 i := 0
475 for k, v := range fields {
476 data[i] = k
477 data[i+1] = v
478 i = i + 2
479 }
480 return data
481}
482
483// With returns a logger initialized with the key-value pairs
484func (l logger) With(keysAndValues Fields) Logger {
485 return logger{log: l.log.With(serializeMap(keysAndValues)...), parent: l.parent}
486}
487
488// Debug logs a message at level Debug on the standard logger.
489func (l logger) Debug(args ...interface{}) {
490 l.log.Debug(args...)
491}
492
493// Debugln logs a message at level Debug on the standard logger with a line feed. Default in any case.
494func (l logger) Debugln(args ...interface{}) {
495 l.log.Debug(args...)
496}
497
498// Debugw logs a message at level Debug on the standard logger.
499func (l logger) Debugf(format string, args ...interface{}) {
500 l.log.Debugf(format, args...)
501}
502
503// Debugw logs a message with some additional context. The variadic key-value
504// pairs are treated as they are in With.
505func (l logger) Debugw(msg string, keysAndValues Fields) {
506 l.log.Debugw(msg, serializeMap(keysAndValues)...)
507}
508
509// Info logs a message at level Info on the standard logger.
510func (l logger) Info(args ...interface{}) {
511 l.log.Info(args...)
512}
513
514// Infoln logs a message at level Info on the standard logger with a line feed. Default in any case.
515func (l logger) Infoln(args ...interface{}) {
516 l.log.Info(args...)
517 //msg := fmt.Sprintln(args...)
518 //l.sourced().Info(msg[:len(msg)-1])
519}
520
521// Infof logs a message at level Info on the standard logger.
522func (l logger) Infof(format string, args ...interface{}) {
523 l.log.Infof(format, args...)
524}
525
526// Infow logs a message with some additional context. The variadic key-value
527// pairs are treated as they are in With.
528func (l logger) Infow(msg string, keysAndValues Fields) {
529 l.log.Infow(msg, serializeMap(keysAndValues)...)
530}
531
532// Warn logs a message at level Warn on the standard logger.
533func (l logger) Warn(args ...interface{}) {
534 l.log.Warn(args...)
535}
536
537// Warnln logs a message at level Warn on the standard logger with a line feed. Default in any case.
538func (l logger) Warnln(args ...interface{}) {
539 l.log.Warn(args...)
540}
541
542// Warnf logs a message at level Warn on the standard logger.
543func (l logger) Warnf(format string, args ...interface{}) {
544 l.log.Warnf(format, args...)
545}
546
547// Warnw logs a message with some additional context. The variadic key-value
548// pairs are treated as they are in With.
549func (l logger) Warnw(msg string, keysAndValues Fields) {
550 l.log.Warnw(msg, serializeMap(keysAndValues)...)
551}
552
553// Error logs a message at level Error on the standard logger.
554func (l logger) Error(args ...interface{}) {
555 l.log.Error(args...)
556}
557
558// Errorln logs a message at level Error on the standard logger with a line feed. Default in any case.
559func (l logger) Errorln(args ...interface{}) {
560 l.log.Error(args...)
561}
562
563// Errorf logs a message at level Error on the standard logger.
564func (l logger) Errorf(format string, args ...interface{}) {
565 l.log.Errorf(format, args...)
566}
567
568// Errorw logs a message with some additional context. The variadic key-value
569// pairs are treated as they are in With.
570func (l logger) Errorw(msg string, keysAndValues Fields) {
571 l.log.Errorw(msg, serializeMap(keysAndValues)...)
572}
573
574// Fatal logs a message at level Fatal on the standard logger.
575func (l logger) Fatal(args ...interface{}) {
576 l.log.Fatal(args...)
577}
578
579// Fatalln logs a message at level Fatal on the standard logger with a line feed. Default in any case.
580func (l logger) Fatalln(args ...interface{}) {
581 l.log.Fatal(args...)
582}
583
584// Fatalf logs a message at level Fatal on the standard logger.
585func (l logger) Fatalf(format string, args ...interface{}) {
586 l.log.Fatalf(format, args...)
587}
588
589// Fatalw logs a message with some additional context. The variadic key-value
590// pairs are treated as they are in With.
591func (l logger) Fatalw(msg string, keysAndValues Fields) {
592 l.log.Fatalw(msg, serializeMap(keysAndValues)...)
593}
594
595// Warning logs a message at level Warn on the standard logger.
596func (l logger) Warning(args ...interface{}) {
597 l.log.Warn(args...)
598}
599
600// Warningln logs a message at level Warn on the standard logger with a line feed. Default in any case.
601func (l logger) Warningln(args ...interface{}) {
602 l.log.Warn(args...)
603}
604
605// Warningf logs a message at level Warn on the standard logger.
606func (l logger) Warningf(format string, args ...interface{}) {
607 l.log.Warnf(format, args...)
608}
609
610// V reports whether verbosity level l is at least the requested verbose level.
611func (l logger) V(level int) bool {
612 return l.parent.Core().Enabled(intToLevel(level))
613}
614
615// With returns a logger initialized with the key-value pairs
616func With(keysAndValues Fields) Logger {
617 return logger{log: getPackageLevelSugaredLogger().With(serializeMap(keysAndValues)...), parent: defaultLogger.parent}
618}
619
620// Debug logs a message at level Debug on the standard logger.
621func Debug(args ...interface{}) {
622 getPackageLevelSugaredLogger().Debug(args...)
623}
624
625// Debugln logs a message at level Debug on the standard logger.
626func Debugln(args ...interface{}) {
627 getPackageLevelSugaredLogger().Debug(args...)
628}
629
630// Debugf logs a message at level Debug on the standard logger.
631func Debugf(format string, args ...interface{}) {
632 getPackageLevelSugaredLogger().Debugf(format, args...)
633}
634
635// Debugw logs a message with some additional context. The variadic key-value
636// pairs are treated as they are in With.
637func Debugw(msg string, keysAndValues Fields) {
638 getPackageLevelSugaredLogger().Debugw(msg, serializeMap(keysAndValues)...)
639}
640
641// Info logs a message at level Info on the standard logger.
642func Info(args ...interface{}) {
643 getPackageLevelSugaredLogger().Info(args...)
644}
645
646// Infoln logs a message at level Info on the standard logger.
647func Infoln(args ...interface{}) {
648 getPackageLevelSugaredLogger().Info(args...)
649}
650
651// Infof logs a message at level Info on the standard logger.
652func Infof(format string, args ...interface{}) {
653 getPackageLevelSugaredLogger().Infof(format, args...)
654}
655
656//Infow logs a message with some additional context. The variadic key-value
657//pairs are treated as they are in With.
658func Infow(msg string, keysAndValues Fields) {
659 getPackageLevelSugaredLogger().Infow(msg, serializeMap(keysAndValues)...)
660}
661
662// Warn logs a message at level Warn on the standard logger.
663func Warn(args ...interface{}) {
664 getPackageLevelSugaredLogger().Warn(args...)
665}
666
667// Warnln logs a message at level Warn on the standard logger.
668func Warnln(args ...interface{}) {
669 getPackageLevelSugaredLogger().Warn(args...)
670}
671
672// Warnf logs a message at level Warn on the standard logger.
673func Warnf(format string, args ...interface{}) {
674 getPackageLevelSugaredLogger().Warnf(format, args...)
675}
676
677// Warnw logs a message with some additional context. The variadic key-value
678// pairs are treated as they are in With.
679func Warnw(msg string, keysAndValues Fields) {
680 getPackageLevelSugaredLogger().Warnw(msg, serializeMap(keysAndValues)...)
681}
682
683// Error logs a message at level Error on the standard logger.
684func Error(args ...interface{}) {
685 getPackageLevelSugaredLogger().Error(args...)
686}
687
688// Errorln logs a message at level Error on the standard logger.
689func Errorln(args ...interface{}) {
690 getPackageLevelSugaredLogger().Error(args...)
691}
692
693// Errorf logs a message at level Error on the standard logger.
694func Errorf(format string, args ...interface{}) {
695 getPackageLevelSugaredLogger().Errorf(format, args...)
696}
697
698// Errorw logs a message with some additional context. The variadic key-value
699// pairs are treated as they are in With.
700func Errorw(msg string, keysAndValues Fields) {
701 getPackageLevelSugaredLogger().Errorw(msg, serializeMap(keysAndValues)...)
702}
703
704// Fatal logs a message at level Fatal on the standard logger.
705func Fatal(args ...interface{}) {
706 getPackageLevelSugaredLogger().Fatal(args...)
707}
708
709// Fatalln logs a message at level Fatal on the standard logger.
710func Fatalln(args ...interface{}) {
711 getPackageLevelSugaredLogger().Fatal(args...)
712}
713
714// Fatalf logs a message at level Fatal on the standard logger.
715func Fatalf(format string, args ...interface{}) {
716 getPackageLevelSugaredLogger().Fatalf(format, args...)
717}
718
719// Fatalw logs a message with some additional context. The variadic key-value
720// pairs are treated as they are in With.
721func Fatalw(msg string, keysAndValues Fields) {
722 getPackageLevelSugaredLogger().Fatalw(msg, serializeMap(keysAndValues)...)
723}
724
725// Warning logs a message at level Warn on the standard logger.
726func Warning(args ...interface{}) {
727 getPackageLevelSugaredLogger().Warn(args...)
728}
729
730// Warningln logs a message at level Warn on the standard logger.
731func Warningln(args ...interface{}) {
732 getPackageLevelSugaredLogger().Warn(args...)
733}
734
735// Warningf logs a message at level Warn on the standard logger.
736func Warningf(format string, args ...interface{}) {
737 getPackageLevelSugaredLogger().Warnf(format, args...)
738}
739
740// V reports whether verbosity level l is at least the requested verbose level.
741func V(level int) bool {
742 return getPackageLevelLogger().V(level)
743}