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 }