// Beego (http://beego.me/) // @description beego is an open-source, high-performance web framework for the Go programming language. // @link http://github.com/astaxie/beego for the canonical source repository // @license http://github.com/astaxie/beego/blob/master/LICENSE // @authors astaxie package logs import ( "fmt" "path" "runtime" "sync" ) const ( // log message levels LevelTrace = iota LevelDebug LevelInfo LevelWarn LevelError LevelCritical ) type loggerType func() LoggerInterface // LoggerInterface defines the behavior of a log provider. type LoggerInterface interface { Init(config string) error WriteMsg(msg string, level int) error Destroy() Flush() } var adapters = make(map[string]loggerType) // Register makes a log provide available by the provided name. // If Register is called twice with the same name or if driver is nil, // it panics. func Register(name string, log loggerType) { if log == nil { panic("logs: Register provide is nil") } if _, dup := adapters[name]; dup { panic("logs: Register called twice for provider " + name) } adapters[name] = log } // BeeLogger is default logger in beego application. // it can contain several providers and log message into all providers. type BeeLogger struct { lock sync.Mutex level int enableFuncCallDepth bool loggerFuncCallDepth int msg chan *logMsg outputs map[string]LoggerInterface } type logMsg struct { level int msg string } // NewLogger returns a new BeeLogger. // channellen means the number of messages in chan. // if the buffering chan is full, logger adapters write to file or other way. func NewLogger(channellen int64) *BeeLogger { bl := new(BeeLogger) bl.loggerFuncCallDepth = 2 bl.msg = make(chan *logMsg, channellen) bl.outputs = make(map[string]LoggerInterface) //bl.SetLogger("console", "") // default output to console go bl.startLogger() return bl } // SetLogger provides a given logger adapter into BeeLogger with config string. // config need to be correct JSON as string: {"interval":360}. func (bl *BeeLogger) SetLogger(adaptername string, config string) error { bl.lock.Lock() defer bl.lock.Unlock() if log, ok := adapters[adaptername]; ok { lg := log() err := lg.Init(config) bl.outputs[adaptername] = lg if err != nil { fmt.Println("logs.BeeLogger.SetLogger: " + err.Error()) return err } } else { return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adaptername) } return nil } // remove a logger adapter in BeeLogger. func (bl *BeeLogger) DelLogger(adaptername string) error { bl.lock.Lock() defer bl.lock.Unlock() if lg, ok := bl.outputs[adaptername]; ok { lg.Destroy() delete(bl.outputs, adaptername) return nil } else { return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adaptername) } } func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { if bl.level > loglevel { return nil } lm := new(logMsg) lm.level = loglevel if bl.enableFuncCallDepth { _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) if ok { _, filename := path.Split(file) lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg) } else { lm.msg = msg } } else { lm.msg = msg } bl.msg <- lm return nil } // set log message level. // if message level (such as LevelTrace) is less than logger level (such as LevelWarn), ignore message. func (bl *BeeLogger) SetLevel(l int) { bl.level = l } // set log funcCallDepth func (bl *BeeLogger) SetLogFuncCallDepth(d int) { bl.loggerFuncCallDepth = d } // enable log funcCallDepth func (bl *BeeLogger) EnableFuncCallDepth(b bool) { bl.enableFuncCallDepth = b } // start logger chan reading. // when chan is full, write logs. func (bl *BeeLogger) startLogger() { for { select { case bm := <-bl.msg: for _, l := range bl.outputs { l.WriteMsg(bm.msg, bm.level) } } } } // log trace level message. func (bl *BeeLogger) Trace(format string, v ...interface{}) { msg := fmt.Sprintf("[T] "+format, v...) bl.writerMsg(LevelTrace, msg) } // log debug level message. func (bl *BeeLogger) Debug(format string, v ...interface{}) { msg := fmt.Sprintf("[D] "+format, v...) bl.writerMsg(LevelDebug, msg) } // log info level message. func (bl *BeeLogger) Info(format string, v ...interface{}) { msg := fmt.Sprintf("[I] "+format, v...) bl.writerMsg(LevelInfo, msg) } // log warn level message. func (bl *BeeLogger) Warn(format string, v ...interface{}) { msg := fmt.Sprintf("[W] "+format, v...) bl.writerMsg(LevelWarn, msg) } // log error level message. func (bl *BeeLogger) Error(format string, v ...interface{}) { msg := fmt.Sprintf("[E] "+format, v...) bl.writerMsg(LevelError, msg) } // log critical level message. func (bl *BeeLogger) Critical(format string, v ...interface{}) { msg := fmt.Sprintf("[C] "+format, v...) bl.writerMsg(LevelCritical, msg) } // flush all chan data. func (bl *BeeLogger) Flush() { for _, l := range bl.outputs { l.Flush() } } // close logger, flush all chan data and destroy all adapters in BeeLogger. func (bl *BeeLogger) Close() { for { if len(bl.msg) > 0 { bm := <-bl.msg for _, l := range bl.outputs { l.WriteMsg(bm.msg, bm.level) } } else { break } } for _, l := range bl.outputs { l.Flush() l.Destroy() } }