github.com/eframework-cn/EP.GO.UTIL@v1.0.0/xlog/log.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package xlog 16 17 import ( 18 "fmt" 19 "log" 20 "os" 21 "strings" 22 "sync" 23 "time" 24 ) 25 26 // RFC5424 log message levels. 27 const ( 28 LevelEmergency = iota 29 LevelAlert 30 LevelCritical 31 LevelError 32 LevelWarning 33 LevelNotice 34 LevelInformational 35 LevelDebug 36 ) 37 38 // levelLogLogger is defined to implement log.Logger 39 // the real log level will be LevelEmergency 40 const levelLoggerImpl = -1 41 42 // Name for adapter with beego official support 43 const ( 44 AdapterConsole = "console" 45 AdapterFile = "file" 46 AdapterMultiFile = "multifile" 47 AdapterMail = "smtp" 48 AdapterConn = "conn" 49 AdapterEs = "es" 50 AdapterJianLiao = "jianliao" 51 AdapterSlack = "slack" 52 AdapterAliLS = "alils" 53 ) 54 55 // Legacy log level constants to ensure backwards compatibility. 56 const ( 57 LevelInfo = LevelInformational 58 LevelTrace = LevelDebug 59 LevelWarn = LevelWarning 60 ) 61 62 type newLoggerFunc func() Logger 63 64 // Logger defines the behavior of a log provider. 65 type Logger interface { 66 Init(config string) error 67 WriteMsg(when time.Time, msg string, level int) error 68 Destroy() 69 Flush() 70 } 71 72 var adapters = make(map[string]newLoggerFunc) 73 var levelPrefix = [LevelDebug + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]"} 74 75 // Register makes a log provide available by the provided name. 76 // If Register is called twice with the same name or if driver is nil, 77 // it panics. 78 func Register(name string, log newLoggerFunc) { 79 if log == nil { 80 panic("logs: Register provide is nil") 81 } 82 if _, dup := adapters[name]; dup { 83 panic("logs: Register called twice for provider " + name) 84 } 85 adapters[name] = log 86 } 87 88 // BeeLogger is default logger in beego application. 89 // it can contain several providers and log message into all providers. 90 type BeeLogger struct { 91 lock sync.Mutex 92 level int 93 init bool 94 enableFuncCallDepth bool 95 loggerFuncCallDepth int 96 asynchronous bool 97 prefix string 98 msgChanLen int64 99 msgChan chan *logMsg 100 signalChan chan string 101 wg sync.WaitGroup 102 outputs []*nameLogger 103 closed bool 104 } 105 106 const defaultAsyncMsgLen = 1e3 107 108 type nameLogger struct { 109 Logger 110 name string 111 } 112 113 type logMsg struct { 114 level int 115 fmt string 116 args []interface{} 117 when time.Time 118 } 119 120 func (this *logMsg) toString(prefix string) string { 121 msg := this.fmt 122 if len(this.args) > 0 { 123 msg = fmt.Sprintf(this.fmt, this.args...) 124 } 125 msg = prefix + " " + msg 126 msg = levelPrefix[this.level] + " " + msg 127 return msg 128 } 129 130 var logMsgPool *sync.Pool 131 132 // NewLogger returns a new BeeLogger. 133 // channelLen means the number of messages in chan(used where asynchronous is true). 134 // if the buffering chan is full, logger adapters write to file or other way. 135 func NewLogger(channelLens ...int64) *BeeLogger { 136 bl := new(BeeLogger) 137 bl.level = LevelDebug 138 bl.loggerFuncCallDepth = 2 139 bl.msgChanLen = append(channelLens, 0)[0] 140 if bl.msgChanLen <= 0 { 141 bl.msgChanLen = defaultAsyncMsgLen 142 } 143 bl.signalChan = make(chan string, 1) 144 bl.setLogger(AdapterConsole) 145 return bl 146 } 147 148 // Async set the log to asynchronous and start the goroutine 149 func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { 150 bl.lock.Lock() 151 defer bl.lock.Unlock() 152 if bl.asynchronous { 153 return bl 154 } 155 bl.asynchronous = true 156 if len(msgLen) > 0 && msgLen[0] > 0 { 157 bl.msgChanLen = msgLen[0] 158 } 159 bl.msgChan = make(chan *logMsg, bl.msgChanLen) 160 logMsgPool = &sync.Pool{ 161 New: func() interface{} { 162 return &logMsg{} 163 }, 164 } 165 bl.wg.Add(1) 166 go bl.startLogger() 167 return bl 168 } 169 170 // SetLogger provides a given logger adapter into BeeLogger with config string. 171 // config need to be correct JSON as string: {"interval":360}. 172 func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { 173 config := append(configs, "{}")[0] 174 for _, l := range bl.outputs { 175 if l.name == adapterName { 176 return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName) 177 } 178 } 179 180 logAdapter, ok := adapters[adapterName] 181 if !ok { 182 return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName) 183 } 184 185 lg := logAdapter() 186 err := lg.Init(config) 187 if err != nil { 188 fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error()) 189 return err 190 } 191 bl.outputs = append(bl.outputs, &nameLogger{name: adapterName, Logger: lg}) 192 return nil 193 } 194 195 // SetLogger provides a given logger adapter into BeeLogger with config string. 196 // config need to be correct JSON as string: {"interval":360}. 197 func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { 198 bl.lock.Lock() 199 defer bl.lock.Unlock() 200 if !bl.init { 201 bl.outputs = []*nameLogger{} 202 bl.init = true 203 } 204 return bl.setLogger(adapterName, configs...) 205 } 206 207 // DelLogger remove a logger adapter in BeeLogger. 208 func (bl *BeeLogger) DelLogger(adapterName string) error { 209 bl.lock.Lock() 210 defer bl.lock.Unlock() 211 outputs := []*nameLogger{} 212 for _, lg := range bl.outputs { 213 if lg.name == adapterName { 214 lg.Destroy() 215 } else { 216 outputs = append(outputs, lg) 217 } 218 } 219 if len(outputs) == len(bl.outputs) { 220 return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName) 221 } 222 bl.outputs = outputs 223 return nil 224 } 225 226 func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) { 227 for _, l := range bl.outputs { 228 err := l.WriteMsg(when, msg, level) 229 if err != nil { 230 fmt.Fprintf(os.Stderr, "unable to WriteMsg to adapter:%v,error:%v\n", l.name, err) 231 } 232 } 233 } 234 235 func (bl *BeeLogger) Write(p []byte) (n int, err error) { 236 if len(p) == 0 { 237 return 0, nil 238 } 239 // writeMsg will always add a '\n' character 240 if p[len(p)-1] == '\n' { 241 p = p[0 : len(p)-1] 242 } 243 // set levelLoggerImpl to ensure all log message will be write out 244 err = bl.WriteMsg(levelLoggerImpl, string(p)) 245 if err == nil { 246 return len(p), err 247 } 248 return 0, err 249 } 250 251 func (bl *BeeLogger) WriteMsg(logLevel int, msg string, v ...interface{}) error { 252 if bl.closed { 253 if len(v) > 0 { 254 msg = fmt.Sprintf(msg, v...) 255 } 256 msg = bl.prefix + " " + msg 257 msg = levelPrefix[logLevel] + " " + msg 258 fmt.Println(msg) 259 return nil 260 } 261 if !bl.init { 262 bl.lock.Lock() 263 bl.setLogger(AdapterConsole) 264 bl.lock.Unlock() 265 } 266 267 when := time.Now() 268 269 if logLevel == levelLoggerImpl { 270 logLevel = LevelEmergency 271 } 272 273 if bl.asynchronous { 274 lm := logMsgPool.Get().(*logMsg) 275 lm.level = logLevel 276 lm.fmt = msg 277 lm.args = v 278 lm.when = when 279 bl.msgChan <- lm 280 } else { 281 if len(v) > 0 { 282 msg = fmt.Sprintf(msg, v...) 283 } 284 msg = bl.prefix + " " + msg 285 msg = levelPrefix[logLevel] + " " + msg 286 bl.writeToLoggers(when, msg, logLevel) 287 } 288 return nil 289 } 290 291 // SetLevel Set log message level. 292 // If message level (such as LevelDebug) is higher than logger level (such as LevelWarning), 293 // log providers will not even be sent the message. 294 func (bl *BeeLogger) SetLevel(l int) { 295 bl.level = l 296 } 297 298 // GetLevel Get Current log message level. 299 func (bl *BeeLogger) GetLevel() int { 300 return bl.level 301 } 302 303 // SetLogFuncCallDepth set log funcCallDepth 304 func (bl *BeeLogger) SetLogFuncCallDepth(d int) { 305 bl.loggerFuncCallDepth = d 306 } 307 308 // GetLogFuncCallDepth return log funcCallDepth for wrapper 309 func (bl *BeeLogger) GetLogFuncCallDepth() int { 310 return bl.loggerFuncCallDepth 311 } 312 313 // EnableFuncCallDepth enable log funcCallDepth 314 func (bl *BeeLogger) EnableFuncCallDepth(b bool) { 315 bl.enableFuncCallDepth = b 316 } 317 318 // set prefix 319 func (bl *BeeLogger) SetPrefix(s string) { 320 bl.prefix = s 321 } 322 323 // start logger chan reading. 324 // when chan is not empty, write logs. 325 func (bl *BeeLogger) startLogger() { 326 gameOver := false 327 for { 328 select { 329 case bm := <-bl.msgChan: 330 bl.writeToLoggers(bm.when, bm.toString(bl.prefix), bm.level) 331 logMsgPool.Put(bm) 332 case sg := <-bl.signalChan: 333 // Now should only send "flush" or "close" to bl.signalChan 334 bl.flush() 335 if sg == "close" { 336 for _, l := range bl.outputs { 337 l.Destroy() 338 } 339 bl.outputs = nil 340 gameOver = true 341 } 342 bl.wg.Done() 343 } 344 if gameOver { 345 break 346 } 347 } 348 } 349 350 // Emergency Log EMERGENCY level message. 351 func (bl *BeeLogger) Emergency(format string, v ...interface{}) { 352 if LevelEmergency > bl.level { 353 return 354 } 355 bl.WriteMsg(LevelEmergency, format, v...) 356 } 357 358 // Alert Log ALERT level message. 359 func (bl *BeeLogger) Alert(format string, v ...interface{}) { 360 if LevelAlert > bl.level { 361 return 362 } 363 bl.WriteMsg(LevelAlert, format, v...) 364 } 365 366 // Critical Log CRITICAL level message. 367 func (bl *BeeLogger) Critical(format string, v ...interface{}) { 368 if LevelCritical > bl.level { 369 return 370 } 371 bl.WriteMsg(LevelCritical, format, v...) 372 } 373 374 // Error Log ERROR level message. 375 func (bl *BeeLogger) Error(format string, v ...interface{}) { 376 if LevelError > bl.level { 377 return 378 } 379 bl.WriteMsg(LevelError, format, v...) 380 } 381 382 // Warning Log WARNING level message. 383 func (bl *BeeLogger) Warning(format string, v ...interface{}) { 384 if LevelWarn > bl.level { 385 return 386 } 387 bl.WriteMsg(LevelWarn, format, v...) 388 } 389 390 // Notice Log NOTICE level message. 391 func (bl *BeeLogger) Notice(format string, v ...interface{}) { 392 if LevelNotice > bl.level { 393 return 394 } 395 bl.WriteMsg(LevelNotice, format, v...) 396 } 397 398 // Informational Log INFORMATIONAL level message. 399 func (bl *BeeLogger) Informational(format string, v ...interface{}) { 400 if LevelInfo > bl.level { 401 return 402 } 403 bl.WriteMsg(LevelInfo, format, v...) 404 } 405 406 // Debug Log DEBUG level message. 407 func (bl *BeeLogger) Debug(format string, v ...interface{}) { 408 if LevelDebug > bl.level { 409 return 410 } 411 bl.WriteMsg(LevelDebug, format, v...) 412 } 413 414 // Warn Log WARN level message. 415 // compatibility alias for Warning() 416 func (bl *BeeLogger) Warn(format string, v ...interface{}) { 417 if LevelWarn > bl.level { 418 return 419 } 420 bl.WriteMsg(LevelWarn, format, v...) 421 } 422 423 // Info Log INFO level message. 424 // compatibility alias for Informational() 425 func (bl *BeeLogger) Info(format string, v ...interface{}) { 426 if LevelInfo > bl.level { 427 return 428 } 429 bl.WriteMsg(LevelInfo, format, v...) 430 } 431 432 // Trace Log TRACE level message. 433 // compatibility alias for Debug() 434 func (bl *BeeLogger) Trace(format string, v ...interface{}) { 435 if LevelDebug > bl.level { 436 return 437 } 438 bl.WriteMsg(LevelDebug, format, v...) 439 } 440 441 // Flush flush all chan data. 442 func (bl *BeeLogger) Flush() { 443 if bl.asynchronous { 444 bl.signalChan <- "flush" 445 bl.wg.Wait() 446 bl.wg.Add(1) 447 return 448 } 449 bl.flush() 450 } 451 452 // Close close logger, flush all chan data and destroy all adapters in BeeLogger. 453 func (bl *BeeLogger) Close() { 454 bl.closed = true 455 if bl.asynchronous { 456 bl.signalChan <- "close" 457 bl.wg.Wait() 458 close(bl.msgChan) 459 } else { 460 bl.flush() 461 for _, l := range bl.outputs { 462 l.Destroy() 463 } 464 bl.outputs = nil 465 } 466 close(bl.signalChan) 467 } 468 469 // Reset close all outputs, and set bl.outputs to nil 470 func (bl *BeeLogger) Reset() { 471 bl.Flush() 472 for _, l := range bl.outputs { 473 l.Destroy() 474 } 475 bl.outputs = nil 476 } 477 478 func (bl *BeeLogger) flush() { 479 if bl.asynchronous { 480 for { 481 if len(bl.msgChan) > 0 { 482 bm := <-bl.msgChan 483 bl.writeToLoggers(bm.when, bm.toString(bl.prefix), bm.level) 484 logMsgPool.Put(bm) 485 continue 486 } 487 break 488 } 489 } 490 for _, l := range bl.outputs { 491 l.Flush() 492 } 493 } 494 495 // beeLogger references the used application logger. 496 var beeLogger = NewLogger() 497 498 // GetBeeLogger returns the default BeeLogger 499 func GetBeeLogger() *BeeLogger { 500 return beeLogger 501 } 502 503 var beeLoggerMap = struct { 504 sync.RWMutex 505 logs map[string]*log.Logger 506 }{ 507 logs: map[string]*log.Logger{}, 508 } 509 510 // GetLogger returns the default BeeLogger 511 func GetLogger(prefixes ...string) *log.Logger { 512 prefix := append(prefixes, "")[0] 513 if prefix != "" { 514 prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix)) 515 } 516 beeLoggerMap.RLock() 517 l, ok := beeLoggerMap.logs[prefix] 518 if ok { 519 beeLoggerMap.RUnlock() 520 return l 521 } 522 beeLoggerMap.RUnlock() 523 beeLoggerMap.Lock() 524 defer beeLoggerMap.Unlock() 525 l, ok = beeLoggerMap.logs[prefix] 526 if !ok { 527 l = log.New(beeLogger, prefix, 0) 528 beeLoggerMap.logs[prefix] = l 529 } 530 return l 531 } 532 533 // Reset will remove all the adapter 534 func Reset() { 535 beeLogger.Reset() 536 } 537 538 // Async set the beelogger with Async mode and hold msglen messages 539 func Async(msgLen ...int64) *BeeLogger { 540 return beeLogger.Async(msgLen...) 541 } 542 543 // SetLevel sets the global log level used by the simple logger. 544 func SetLevel(l int) { 545 beeLogger.SetLevel(l) 546 } 547 548 // SetPrefix sets the prefix 549 func SetPrefix(s string) { 550 beeLogger.SetPrefix(s) 551 } 552 553 // EnableFuncCallDepth enable log funcCallDepth 554 func EnableFuncCallDepth(b bool) { 555 beeLogger.enableFuncCallDepth = b 556 } 557 558 // SetLogFuncCall set the CallDepth, default is 4 559 func SetLogFuncCall(b bool) { 560 beeLogger.EnableFuncCallDepth(b) 561 beeLogger.SetLogFuncCallDepth(4) 562 } 563 564 // SetLogFuncCallDepth set log funcCallDepth 565 func SetLogFuncCallDepth(d int) { 566 beeLogger.loggerFuncCallDepth = d 567 } 568 569 // SetLogger sets a new logger. 570 func SetLogger(adapter string, config ...string) error { 571 return beeLogger.SetLogger(adapter, config...) 572 } 573 574 // Emergency logs a message at emergency level. 575 func Emergency(f interface{}, v ...interface{}) { 576 beeLogger.Emergency(Format(f, v...)) 577 } 578 579 // Alert logs a message at alert level. 580 func Alert(f interface{}, v ...interface{}) { 581 beeLogger.Alert(Format(f, v...)) 582 } 583 584 // Critical logs a message at critical level. 585 func Critical(f interface{}, v ...interface{}) { 586 beeLogger.Critical(Format(f, v...)) 587 } 588 589 // Error logs a message at error level. 590 func Error(f interface{}, v ...interface{}) { 591 beeLogger.Error(Format(f, v...)) 592 } 593 594 // Warning logs a message at warning level. 595 func Warning(f interface{}, v ...interface{}) { 596 beeLogger.Warn(Format(f, v...)) 597 } 598 599 // Warn compatibility alias for Warning() 600 func Warn(f interface{}, v ...interface{}) { 601 beeLogger.Warn(Format(f, v...)) 602 } 603 604 // Notice logs a message at notice level. 605 func Notice(f interface{}, v ...interface{}) { 606 beeLogger.Notice(Format(f, v...)) 607 } 608 609 // Informational logs a message at info level. 610 func Informational(f interface{}, v ...interface{}) { 611 beeLogger.Info(Format(f, v...)) 612 } 613 614 // Info compatibility alias for Warning() 615 func Info(f interface{}, v ...interface{}) { 616 beeLogger.Info(Format(f, v...)) 617 } 618 619 // Debug logs a message at debug level. 620 func Debug(f interface{}, v ...interface{}) { 621 beeLogger.Debug(Format(f, v...)) 622 } 623 624 // Trace logs a message at trace level. 625 // compatibility alias for Warning() 626 func Trace(f interface{}, v ...interface{}) { 627 beeLogger.Trace(Format(f, v...)) 628 } 629 630 func Format(f interface{}, v ...interface{}) string { 631 var msg string 632 switch f.(type) { 633 case string: 634 msg = f.(string) 635 if len(v) == 0 { 636 return msg 637 } 638 if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") { 639 //format string 640 } else { 641 //do not contain format char 642 msg += strings.Repeat(" %v", len(v)) 643 } 644 default: 645 msg = fmt.Sprint(f) 646 if len(v) == 0 { 647 return msg 648 } 649 msg += strings.Repeat(" %v", len(v)) 650 } 651 return fmt.Sprintf(msg, v...) 652 }