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