github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/zlog/global.go (about)

     1  package zlog
     2  
     3  import (
     4  	"fmt"
     5  	"sync/atomic"
     6  
     7  	"go.uber.org/zap"
     8  
     9  	"github.com/jxskiss/gopkg/v2/internal/logfilter"
    10  )
    11  
    12  var globals struct {
    13  	Default, Skip1 struct {
    14  		L *zap.Logger
    15  		S *zap.SugaredLogger
    16  	}
    17  	Props *Properties
    18  
    19  	// Level is a copy of Props.level for fast path accessing.
    20  	Level atomic.Int32
    21  }
    22  
    23  func init() {
    24  	ReplaceGlobals(mustNewGlobalLogger(&Config{}))
    25  }
    26  
    27  // Properties holds some information about the global config and logger.
    28  type Properties struct {
    29  	cfg           GlobalConfig
    30  	disableCaller bool
    31  	level         zap.AtomicLevel
    32  	traceFilter   *logfilter.FileNameFilter
    33  	closers       []func()
    34  }
    35  
    36  // CloseWriters close all writers associated with this Properties object.
    37  func (p *Properties) CloseWriters() {
    38  	runClosers(p.closers)
    39  }
    40  
    41  func (p *Properties) setupGlobals() func() {
    42  	if p.cfg.MethodNameKey == "" {
    43  		p.cfg.MethodNameKey = defaultMethodNameKey
    44  	}
    45  	var resetStdLog = func() {}
    46  	if p.cfg.RedirectStdLog {
    47  		resetStdLog = redirectStdLog(L().Logger, p.disableCaller)
    48  	}
    49  	p.compileTraceFilter()
    50  	globals.Level.Store(int32(p.level.Level()))
    51  	return func() {
    52  		resetStdLog()
    53  	}
    54  }
    55  
    56  // ReplaceGlobals replaces the global Logger and SugaredLogger,
    57  // and returns a function to restore the original values.
    58  //
    59  // It is meant to be called at program startup, library code shall not call
    60  // this function.
    61  func ReplaceGlobals(logger *zap.Logger, props *Properties) func() {
    62  	oldL, oldP := globals.Default.L, globals.Props
    63  
    64  	globals.Default.L = logger
    65  	globals.Default.S = logger.Sugar()
    66  	globals.Skip1.L = logger.WithOptions(zap.AddCallerSkip(1))
    67  	globals.Skip1.S = globals.Skip1.L.Sugar()
    68  	globals.Props = props
    69  
    70  	resetProps := props.setupGlobals()
    71  	zap.ReplaceGlobals(logger)
    72  
    73  	return func() {
    74  		resetProps()
    75  		ReplaceGlobals(oldL, oldP)
    76  	}
    77  }
    78  
    79  // SetDevelopment is a shortcut of SetupGlobals with default configuration
    80  // for development. It sets the global logger in development mode,
    81  // and redirects output from the standard log library's package-global
    82  // logger to the global logger in this package.
    83  //
    84  // It is meant to be called at program startup, when you run in development
    85  // mode, for production mode, please check SetupGlobals and ReplaceGlobals.
    86  func SetDevelopment() {
    87  	cfg := &Config{}
    88  	cfg.Development = true
    89  	cfg.RedirectStdLog = true
    90  	ReplaceGlobals(mustNewGlobalLogger(cfg))
    91  }
    92  
    93  // SetupGlobals setups the global loggers in this package and zap library.
    94  // By default, global loggers are set with default configuration with info
    95  // level and json format, you may use this function to change the default
    96  // loggers.
    97  //
    98  // See Config and GlobalConfig for available configurations.
    99  //
   100  // It is meant to be called at program startup, library code shall not call
   101  // this function.
   102  func SetupGlobals(cfg *Config, opts ...zap.Option) {
   103  	ReplaceGlobals(mustNewGlobalLogger(cfg, opts...))
   104  }
   105  
   106  func mustNewGlobalLogger(cfg *Config, opts ...zap.Option) (*zap.Logger, *Properties) {
   107  	logger, props, err := New(cfg, opts...)
   108  	if err != nil {
   109  		panic("zlog: invalid config to initialize logger: " + err.Error())
   110  	}
   111  	return logger, props
   112  }
   113  
   114  // CloseWriters close all writers opened by the global logger.
   115  func CloseWriters() {
   116  	globals.Props.CloseWriters()
   117  }
   118  
   119  // GetLevel gets the global logging level.
   120  func GetLevel() Level { return globals.Props.level.Level() }
   121  
   122  // SetLevel modifies the global logging level on the fly.
   123  // It's safe for concurrent use.
   124  func SetLevel(lvl Level) {
   125  	globals.Props.level.SetLevel(lvl)
   126  	globals.Level.Store(int32(lvl))
   127  }
   128  
   129  // L returns the global Logger, which can be reconfigured with
   130  // SetupGlobals and ReplaceGlobals.
   131  func L() Logger { return Logger{Logger: globals.Default.L} }
   132  
   133  // S returns the global SugaredLogger, which can be reconfigured with
   134  // SetupGlobals and ReplaceGlobals.
   135  func S() SugaredLogger { return SugaredLogger{SugaredLogger: globals.Default.S} }
   136  
   137  // Sync flushes any buffered log entries.
   138  func Sync() error {
   139  	// Since all global loggers share a same underlying core,
   140  	// calling L().Sync() is enough to flush all pending log messages.
   141  	return L().Sync()
   142  }
   143  
   144  // -------- global logging functions -------- //
   145  
   146  func _l() Logger        { return Logger{Logger: globals.Skip1.L} }
   147  func _s() SugaredLogger { return SugaredLogger{SugaredLogger: globals.Skip1.S} }
   148  
   149  func Debug(msg string, fields ...zap.Field)  { _l().Debug(msg, fields...) }
   150  func Info(msg string, fields ...zap.Field)   { _l().Info(msg, fields...) }
   151  func Warn(msg string, fields ...zap.Field)   { _l().Warn(msg, fields...) }
   152  func Error(msg string, fields ...zap.Field)  { _l().Error(msg, fields...) }
   153  func DPanic(msg string, fields ...zap.Field) { _l().DPanic(msg, fields...) }
   154  func Panic(msg string, fields ...zap.Field)  { _l().Panic(msg, fields...) }
   155  func Fatal(msg string, fields ...zap.Field)  { _l().Fatal(msg, fields...) }
   156  
   157  func Debugf(format string, args ...any)  { _s().Debugf(format, args...) }
   158  func Infof(format string, args ...any)   { _s().Infof(format, args...) }
   159  func Warnf(format string, args ...any)   { _s().Warnf(format, args...) }
   160  func Errorf(format string, args ...any)  { _s().Errorf(format, args...) }
   161  func DPanicf(format string, args ...any) { _s().DPanicf(format, args...) }
   162  func Panicf(format string, args ...any)  { _s().Panicf(format, args...) }
   163  func Fatalf(format string, args ...any)  { _s().Fatalf(format, args...) }
   164  
   165  // Print uses fmt.Sprint to log a message at InfoLevel if it's enabled.
   166  //
   167  // It has same signature with log.Print, which helps to migrate from the
   168  // standard library to this package.
   169  func Print(args ...any) {
   170  	if len(args) > 0 {
   171  		s, _ := args[0].(string)
   172  		if lvl, ok := detectLevel(s); ok {
   173  			if GetLevel().Enabled(lvl) {
   174  				msg := formatMessage("", args)
   175  				_l().Log(lvl, msg)
   176  			}
   177  			return
   178  		}
   179  	}
   180  	_s().Info(args...)
   181  }
   182  
   183  // Printf logs a message at InfoLevel if it's enabled.
   184  //
   185  // It has same signature with log.Printf, which helps to migrate from the
   186  // standard library to this package.
   187  func Printf(format string, args ...any) {
   188  	if lvl, ok := detectLevel(format); ok {
   189  		if GetLevel().Enabled(lvl) {
   190  			msg := formatMessage(format, args)
   191  			_l().Log(lvl, msg)
   192  		}
   193  		return
   194  	}
   195  	_s().Infof(format, args...)
   196  }
   197  
   198  // Println logs a message at InfoLevel if it's enabled.
   199  //
   200  // It has same signature with log.Println, which helps to migrate from the
   201  // standard library to this package.
   202  func Println(args ...any) {
   203  	if len(args) > 0 {
   204  		s, _ := args[0].(string)
   205  		if lvl, ok := detectLevel(s); ok {
   206  			if GetLevel().Enabled(lvl) {
   207  				msg := fmt.Sprintln(args...)
   208  				_l().Log(lvl, msg[:len(msg)-1])
   209  			}
   210  			return
   211  		}
   212  	}
   213  	_s().Infoln(args...)
   214  }