gitee.com/quant1x/gox@v1.21.2/logger/logger.go (about) 1 package logger 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "gitee.com/quant1x/gox/api" 8 "gitee.com/quant1x/gox/cache" 9 "gitee.com/quant1x/gox/mdc" 10 "gitee.com/quant1x/gox/signal" 11 "os" 12 "path/filepath" 13 "reflect" 14 "runtime" 15 "sync" 16 "time" 17 ) 18 19 const ( 20 DEBUG LogLevel = iota 21 INFO 22 WARN 23 ERROR 24 OFF 25 FATAL 26 ) 27 28 const ( 29 loggerRollerDays int = 7 // 保持7天 30 loggerLocalSkip = 2 31 timeFmtTimestamp = "2006-01-02T15:04:05.000" 32 timeFmtHour = "2006010215" 33 timeFmtDay = "20060102" 34 loggerTraceId = mdc.APP_TRACEID 35 ) 36 37 var ( 38 loggerPath string 39 logLevel = DEBUG 40 logQueue = make(chan *logValue, 10000) 41 loggerMap sync.Map 42 logMutex sync.RWMutex 43 currUnixTime int64 44 currDateHour string 45 currDateDay string 46 finished chan struct{} 47 pool cache.Pool[logValue] 48 ) 49 50 type Logger struct { 51 name string 52 writer LogWriter 53 } 54 type LogLevel uint8 55 56 type logValue struct { 57 level LogLevel 58 value []byte 59 fileNo string 60 writer LogWriter 61 fatal bool 62 } 63 64 func init() { 65 now := time.Now() 66 currUnixTime = now.Unix() 67 currDateHour = now.Format(timeFmtHour) 68 currDateDay = now.Format(timeFmtDay) 69 finished = make(chan struct{}) 70 go func() { 71 tm := time.NewTimer(time.Millisecond) 72 for { 73 now := time.Now() 74 d := time.Second - time.Duration(now.Nanosecond()) 75 tm.Reset(d) 76 <-tm.C 77 now = time.Now() 78 logMutex.Lock() 79 currUnixTime = now.Unix() 80 currDateHour = now.Format(timeFmtHour) 81 currDateDay = now.Format(timeFmtDay) 82 logMutex.Unlock() 83 } 84 }() 85 go flushLog(true) 86 87 // 创建监听退出chan 88 sigs := signal.Notify() 89 90 _, cancel := context.WithCancel(context.Background()) 91 92 go func() { 93 s := <-sigs 94 Infof("exit sign, [%+v]", s) 95 FlushLogger() 96 fmt.Println("exit", s) 97 cancel() 98 os.Exit(0) 99 }() 100 101 } 102 103 func (lv *LogLevel) String() string { 104 switch *lv { 105 case DEBUG: 106 return "DEBUG" 107 case INFO: 108 return "INFO" 109 case WARN: 110 return "WARN" 111 case ERROR: 112 return "ERROR" 113 case FATAL: 114 return "FATAL" 115 default: 116 return "UNKNOWN" 117 } 118 } 119 120 // SetLogPath 设置日志路径, 默认是INFO级别日志 121 // 122 // Deprecated: 推荐使用 InitLogger 123 func SetLogPath(path string) { 124 InitLogger(path, INFO) 125 } 126 127 // InitLogger 初始化 128 func InitLogger(path string, level ...LogLevel) { 129 // 日志路径非空, 赋值 130 if !api.IsEmpty(path) { 131 loggerPath = path 132 } 133 name := ApplicationName() 134 loggerPath = filepath.Join(loggerPath, name) 135 136 // 日志级别默认是INFO 137 optLevel := INFO 138 if len(level) > 0 { 139 optLevel = level[0] 140 } 141 SetLevel(optLevel) 142 } 143 144 // GetLogger return an logger instance 145 func GetLogger(name string) *Logger { 146 v, found := loggerMap.Load(name) 147 if found { 148 return v.(*Logger) 149 } 150 lg := &Logger{ 151 name: name, 152 writer: &ConsoleWriter{}, 153 } 154 _ = lg.SetDayRoller(loggerPath, loggerRollerDays) 155 loggerMap.Store(name, lg) 156 return lg 157 } 158 159 func SetLevel(level LogLevel) { 160 logLevel = level 161 } 162 163 // IsDebug 是否DEBUG模式 164 func IsDebug() bool { 165 if DEBUG < logLevel { 166 return false 167 } 168 return true 169 } 170 171 func StringToLevel(level string) LogLevel { 172 switch level { 173 case "DEBUG": 174 return DEBUG 175 case "INFO": 176 return INFO 177 case "WARN": 178 return WARN 179 case "ERROR": 180 return ERROR 181 case "FATAL": 182 return FATAL 183 default: 184 return DEBUG 185 } 186 } 187 188 func (l *Logger) SetLogName(name string) { 189 l.name = name 190 } 191 192 func (l *Logger) SetFileRoller(logpath string, num int, sizeMB int) error { 193 if err := os.MkdirAll(logpath, 0755); err != nil { 194 panic(err) 195 } 196 w := NewRollFileWriter(logpath, l.name, num, sizeMB) 197 l.writer = w 198 return nil 199 } 200 201 func (l *Logger) IsConsoleWriter() bool { 202 if reflect.TypeOf(l.writer) == reflect.TypeOf(&ConsoleWriter{}) { 203 return true 204 } 205 return false 206 } 207 208 func (l *Logger) SetWriter(w LogWriter) { 209 l.writer = w 210 } 211 212 func (l *Logger) SetDayRoller(logpath string, num int) error { 213 if err := os.MkdirAll(logpath, 0755); err != nil { 214 return err 215 } 216 w := NewDateWriter(logpath, l.name, DAY, num) 217 l.writer = w 218 return nil 219 } 220 221 func (l *Logger) SetHourRoller(logpath string, num int) error { 222 if err := os.MkdirAll(logpath, 0755); err != nil { 223 return err 224 } 225 w := NewDateWriter(logpath, l.name, HOUR, num) 226 l.writer = w 227 return nil 228 } 229 230 func (l *Logger) SetConsole() { 231 l.writer = &ConsoleWriter{} 232 } 233 234 func (l *Logger) Debug(v ...any) { 235 l.writef(loggerLocalSkip, DEBUG, "", v) 236 } 237 238 func (l *Logger) Info(v ...any) { 239 l.writef(loggerLocalSkip, INFO, "", v) 240 } 241 242 func (l *Logger) Warn(v ...any) { 243 l.writef(loggerLocalSkip, WARN, "", v) 244 } 245 246 func (l *Logger) Error(v ...any) { 247 l.writef(loggerLocalSkip, ERROR, "", v) 248 } 249 250 func (l *Logger) Debugf(format string, v ...any) { 251 l.writef(loggerLocalSkip, DEBUG, format, v) 252 } 253 254 func (l *Logger) Infof(format string, v ...any) { 255 l.writef(loggerLocalSkip, INFO, format, v) 256 } 257 258 func (l *Logger) Warnf(format string, v ...any) { 259 l.writef(loggerLocalSkip, WARN, format, v) 260 } 261 262 func (l *Logger) Errorf(format string, v ...any) { 263 l.writef(loggerLocalSkip, ERROR, format, v) 264 } 265 266 func (l *Logger) Fatal(v ...any) { 267 l.writef(loggerLocalSkip, FATAL, "", v) 268 waitForExit() 269 } 270 271 func (l *Logger) Fatalf(format string, v ...any) { 272 l.writef(loggerLocalSkip, FATAL, format, v) 273 waitForExit() 274 } 275 276 func getTraceId() string { 277 traceId := mdc.Get(loggerTraceId) 278 t := reflect.ValueOf(traceId) 279 if t.Kind() == reflect.String { 280 return t.String() 281 } 282 return "" 283 } 284 285 func (l *Logger) writef(skip int, level LogLevel, format string, v []any) { 286 if level < logLevel { 287 return 288 } 289 290 t := time.Now() 291 buf := bytes.NewBuffer(nil) 292 if l.writer.NeedPrefix() { 293 traceId := getTraceId() 294 _, _ = fmt.Fprintf(buf, "%s|%s|", t.Format(timeFmtTimestamp), traceId) 295 if logLevel == DEBUG { 296 _, file, line, ok := runtime.Caller(skip) 297 if !ok { 298 file = "???" 299 line = 0 300 } else { 301 file = filepath.Base(file) 302 } 303 _, _ = fmt.Fprintf(buf, "%s:%d|", file, line) 304 } 305 } 306 buf.WriteString(level.String()) 307 buf.WriteByte('|') 308 309 if format == "" { 310 _, _ = fmt.Fprint(buf, v...) 311 } else { 312 _, _ = fmt.Fprintf(buf, format, v...) 313 } 314 if l.writer.NeedPrefix() { 315 buf.WriteByte('\n') 316 } 317 lv := pool.Acquire() 318 lv.value = buf.Bytes() 319 lv.writer = l.writer 320 lv.fatal = level == FATAL 321 logQueue <- lv 322 } 323 324 func FlushLogger() { 325 flushLog(false) 326 } 327 328 // 等待结束信号并退出 329 func waitForExit() { 330 <-finished 331 os.Exit(-1) 332 } 333 334 func refreshLogFile(v *logValue) { 335 if v == nil { 336 return 337 } 338 v.writer.Write(v.value) 339 defer pool.Release(v) 340 if v == nil || !v.fatal { 341 return 342 } 343 // 致命的日志, 同时输出到控制台 344 fmt.Println(api.Bytes2String(v.value)) 345 // 发送结束信号 346 finished <- struct{}{} 347 } 348 349 func flushLog(sync bool) { 350 if sync { 351 for v := range logQueue { 352 refreshLogFile(v) 353 } 354 } else { 355 for { 356 select { 357 case v := <-logQueue: 358 refreshLogFile(v) 359 continue 360 default: 361 return 362 } 363 } 364 } 365 } 366 367 func Info(v ...any) { 368 logger := GetLogger("runtime") 369 logger.writef(loggerLocalSkip, INFO, "", v) 370 } 371 372 func Infof(format string, v ...any) { 373 logger := GetLogger("runtime") 374 logger.writef(loggerLocalSkip, INFO, format, v) 375 } 376 377 func Debug(v ...any) { 378 logger := GetLogger("debug") 379 logger.writef(loggerLocalSkip, DEBUG, "", v) 380 } 381 382 func Debugf(format string, v ...any) { 383 logger := GetLogger("debug") 384 logger.writef(loggerLocalSkip, DEBUG, format, v) 385 } 386 387 func Warn(v ...any) { 388 logger := GetLogger("warn") 389 logger.writef(loggerLocalSkip, WARN, "", v) 390 } 391 392 func Warnf(format string, v ...any) { 393 logger := GetLogger("warn") 394 logger.writef(loggerLocalSkip, WARN, format, v) 395 } 396 397 func Error(v ...any) { 398 logger := GetLogger("error") 399 logger.writef(loggerLocalSkip, ERROR, "", v) 400 } 401 402 func Errorf(format string, v ...any) { 403 logger := GetLogger("error") 404 logger.writef(loggerLocalSkip, ERROR, format, v) 405 } 406 407 func Fatal(v ...any) { 408 logger := GetLogger("error") 409 logger.writef(loggerLocalSkip, FATAL, "", v) 410 waitForExit() 411 } 412 413 func Fatalf(format string, v ...any) { 414 logger := GetLogger("error") 415 logger.writef(loggerLocalSkip, FATAL, format, v) 416 waitForExit() 417 }