|
|
@@ -8,324 +8,167 @@ import (
|
|
|
"fmt"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
- "runtime"
|
|
|
"strings"
|
|
|
- "sync"
|
|
|
-)
|
|
|
|
|
|
-var (
|
|
|
- loggers []*Logger
|
|
|
+ "gopkg.in/ini.v1"
|
|
|
+
|
|
|
+ "github.com/inconshreveable/log15"
|
|
|
)
|
|
|
|
|
|
-func NewLogger(bufLen int64, mode, config string) {
|
|
|
- logger := newLogger(bufLen)
|
|
|
+var rootLogger log15.Logger
|
|
|
+var loggersToClose []DisposableHandler
|
|
|
|
|
|
- isExist := false
|
|
|
- for _, l := range loggers {
|
|
|
- if l.adapter == mode {
|
|
|
- isExist = true
|
|
|
- l = logger
|
|
|
- }
|
|
|
- }
|
|
|
- if !isExist {
|
|
|
- loggers = append(loggers, logger)
|
|
|
- }
|
|
|
- if err := logger.SetLogger(mode, config); err != nil {
|
|
|
- Fatal(1, "Fail to set logger(%s): %v", mode, err)
|
|
|
- }
|
|
|
+func init() {
|
|
|
+ loggersToClose = make([]DisposableHandler, 0)
|
|
|
+ rootLogger = log15.Root()
|
|
|
}
|
|
|
|
|
|
-// this helps you work around the performance annoyance mentioned in
|
|
|
-// https://github.com/grafana/grafana/issues/4055
|
|
|
-// until we refactor this library completely
|
|
|
-func Level(level LogLevel) {
|
|
|
- for i := range loggers {
|
|
|
- loggers[i].level = level
|
|
|
- }
|
|
|
+func New(logger string, ctx ...interface{}) Logger {
|
|
|
+ params := append([]interface{}{"logger", logger}, ctx...)
|
|
|
+ return rootLogger.New(params...)
|
|
|
}
|
|
|
|
|
|
func Trace(format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Trace(format, v...)
|
|
|
- }
|
|
|
+ rootLogger.Debug(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
func Debug(format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Debug(format, v...)
|
|
|
- }
|
|
|
+ rootLogger.Debug(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
-func Info(format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Info(format, v...)
|
|
|
- }
|
|
|
+func Debug2(message string, v ...interface{}) {
|
|
|
+ rootLogger.Debug(message, v...)
|
|
|
}
|
|
|
|
|
|
-func Warn(format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Warn(format, v...)
|
|
|
- }
|
|
|
+func Info(format string, v ...interface{}) {
|
|
|
+ rootLogger.Info(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
-func Error(skip int, format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Error(skip, format, v...)
|
|
|
- }
|
|
|
+func Info2(message string, v ...interface{}) {
|
|
|
+ rootLogger.Info(message, v...)
|
|
|
}
|
|
|
|
|
|
-func Critical(skip int, format string, v ...interface{}) {
|
|
|
- for _, logger := range loggers {
|
|
|
- logger.Critical(skip, format, v...)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func Fatal(skip int, format string, v ...interface{}) {
|
|
|
- Error(skip, format, v...)
|
|
|
- for _, l := range loggers {
|
|
|
- l.Close()
|
|
|
- }
|
|
|
- os.Exit(1)
|
|
|
+func Warn(format string, v ...interface{}) {
|
|
|
+ rootLogger.Warn(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
-func Close() {
|
|
|
- for _, l := range loggers {
|
|
|
- l.Close()
|
|
|
- // delete the logger.
|
|
|
- l = nil
|
|
|
- }
|
|
|
- // clear the loggers slice.
|
|
|
- loggers = nil
|
|
|
+func Warn2(message string, v ...interface{}) {
|
|
|
+ rootLogger.Warn(message, v...)
|
|
|
}
|
|
|
|
|
|
-// .___ __ _____
|
|
|
-// | | _____/ |_ ____________/ ____\____ ____ ____
|
|
|
-// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
|
|
|
-// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/
|
|
|
-// |___|___| /__| \___ >__| |__| (____ /\___ >___ >
|
|
|
-// \/ \/ \/ \/ \/
|
|
|
-
|
|
|
-type LogLevel int
|
|
|
-
|
|
|
-const (
|
|
|
- TRACE LogLevel = iota
|
|
|
- DEBUG
|
|
|
- INFO
|
|
|
- WARN
|
|
|
- ERROR
|
|
|
- CRITICAL
|
|
|
- FATAL
|
|
|
-)
|
|
|
-
|
|
|
-// LoggerInterface represents behaviors of a logger provider.
|
|
|
-type LoggerInterface interface {
|
|
|
- Init(config string) error
|
|
|
- WriteMsg(msg string, skip int, level LogLevel) error
|
|
|
- Destroy()
|
|
|
- Flush()
|
|
|
+func Error(skip int, format string, v ...interface{}) {
|
|
|
+ rootLogger.Error(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
-type loggerType func() LoggerInterface
|
|
|
-
|
|
|
-var adapters = make(map[string]loggerType)
|
|
|
-
|
|
|
-// Register registers given logger provider to adapters.
|
|
|
-func Register(name string, log loggerType) {
|
|
|
- if log == nil {
|
|
|
- panic("log: register provider is nil")
|
|
|
- }
|
|
|
- if _, dup := adapters[name]; dup {
|
|
|
- panic("log: register called twice for provider \"" + name + "\"")
|
|
|
- }
|
|
|
- adapters[name] = log
|
|
|
+func Error2(message string, v ...interface{}) {
|
|
|
+ rootLogger.Error(message, v...)
|
|
|
}
|
|
|
|
|
|
-type logMsg struct {
|
|
|
- skip int
|
|
|
- level LogLevel
|
|
|
- msg string
|
|
|
+func Critical(skip int, format string, v ...interface{}) {
|
|
|
+ rootLogger.Crit(fmt.Sprintf(format, v))
|
|
|
}
|
|
|
|
|
|
-// Logger is default logger in beego application.
|
|
|
-// it can contain several providers and log message into all providers.
|
|
|
-type Logger struct {
|
|
|
- adapter string
|
|
|
- lock sync.Mutex
|
|
|
- level LogLevel
|
|
|
- msg chan *logMsg
|
|
|
- outputs map[string]LoggerInterface
|
|
|
- quit chan bool
|
|
|
+func Fatal(skip int, format string, v ...interface{}) {
|
|
|
+ rootLogger.Crit(fmt.Sprintf(format, v))
|
|
|
+ Close()
|
|
|
+ os.Exit(1)
|
|
|
}
|
|
|
|
|
|
-// newLogger initializes and returns a new logger.
|
|
|
-func newLogger(buffer int64) *Logger {
|
|
|
- l := &Logger{
|
|
|
- msg: make(chan *logMsg, buffer),
|
|
|
- outputs: make(map[string]LoggerInterface),
|
|
|
- quit: make(chan bool),
|
|
|
+func Close() {
|
|
|
+ for _, logger := range loggersToClose {
|
|
|
+ logger.Close()
|
|
|
}
|
|
|
- go l.StartLogger()
|
|
|
- return l
|
|
|
+ loggersToClose = make([]DisposableHandler, 0)
|
|
|
}
|
|
|
|
|
|
-// SetLogger sets new logger instanse with given logger adapter and config.
|
|
|
-func (l *Logger) SetLogger(adapter string, config string) error {
|
|
|
- l.lock.Lock()
|
|
|
- defer l.lock.Unlock()
|
|
|
- if log, ok := adapters[adapter]; ok {
|
|
|
- lg := log()
|
|
|
- if err := lg.Init(config); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- l.outputs[adapter] = lg
|
|
|
- l.adapter = adapter
|
|
|
- } else {
|
|
|
- panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
|
|
|
- }
|
|
|
- return nil
|
|
|
+var logLevels = map[string]log15.Lvl{
|
|
|
+ "Trace": log15.LvlDebug,
|
|
|
+ "Debug": log15.LvlDebug,
|
|
|
+ "Info": log15.LvlInfo,
|
|
|
+ "Warn": log15.LvlWarn,
|
|
|
+ "Error": log15.LvlError,
|
|
|
+ "Critical": log15.LvlCrit,
|
|
|
}
|
|
|
|
|
|
-// DelLogger removes a logger adapter instance.
|
|
|
-func (l *Logger) DelLogger(adapter string) error {
|
|
|
- l.lock.Lock()
|
|
|
- defer l.lock.Unlock()
|
|
|
- if lg, ok := l.outputs[adapter]; ok {
|
|
|
- lg.Destroy()
|
|
|
- delete(l.outputs, adapter)
|
|
|
- } else {
|
|
|
- panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
|
|
|
- }
|
|
|
- return nil
|
|
|
-}
|
|
|
+func getLogLevel(key string, defaultName string, cfg *ini.File) (string, log15.Lvl) {
|
|
|
+ levelName := cfg.Section(key).Key("level").In(defaultName, []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
|
|
|
|
|
|
-func (l *Logger) writerMsg(skip int, level LogLevel, msg string) error {
|
|
|
- lm := &logMsg{
|
|
|
- skip: skip,
|
|
|
- level: level,
|
|
|
+ level, ok := logLevels[levelName]
|
|
|
+ if !ok {
|
|
|
+ rootLogger.Error("Unknown log level", "level", levelName)
|
|
|
}
|
|
|
|
|
|
- // Only error information needs locate position for debugging.
|
|
|
- if lm.level >= ERROR {
|
|
|
- pc, file, line, ok := runtime.Caller(skip)
|
|
|
- if ok {
|
|
|
- // Get caller function name.
|
|
|
- fn := runtime.FuncForPC(pc)
|
|
|
- var fnName string
|
|
|
- if fn == nil {
|
|
|
- fnName = "?()"
|
|
|
- } else {
|
|
|
- fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
|
|
|
- }
|
|
|
-
|
|
|
- lm.msg = fmt.Sprintf("[%s:%d %s] %s", filepath.Base(file), line, fnName, msg)
|
|
|
- } else {
|
|
|
- lm.msg = msg
|
|
|
- }
|
|
|
- } else {
|
|
|
- lm.msg = msg
|
|
|
- }
|
|
|
- l.msg <- lm
|
|
|
- return nil
|
|
|
+ return levelName, level
|
|
|
}
|
|
|
|
|
|
-// StartLogger starts logger chan reading.
|
|
|
-func (l *Logger) StartLogger() {
|
|
|
- for {
|
|
|
- select {
|
|
|
- case bm := <-l.msg:
|
|
|
- for _, l := range l.outputs {
|
|
|
- if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
|
|
|
- fmt.Println("ERROR, unable to WriteMsg:", err)
|
|
|
- }
|
|
|
- }
|
|
|
- case <-l.quit:
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) {
|
|
|
+ Close()
|
|
|
|
|
|
-// Flush flushs all chan data.
|
|
|
-func (l *Logger) Flush() {
|
|
|
- for _, l := range l.outputs {
|
|
|
- l.Flush()
|
|
|
- }
|
|
|
-}
|
|
|
+ defaultLevelName, _ := getLogLevel("log", "Info", cfg)
|
|
|
+ handlers := make([]log15.Handler, 0)
|
|
|
|
|
|
-// Close closes logger, flush all chan data and destroy all adapter instances.
|
|
|
-func (l *Logger) Close() {
|
|
|
- l.quit <- true
|
|
|
- for {
|
|
|
- if len(l.msg) > 0 {
|
|
|
- bm := <-l.msg
|
|
|
- for _, l := range l.outputs {
|
|
|
- if err := l.WriteMsg(bm.msg, bm.skip, bm.level); err != nil {
|
|
|
- fmt.Println("ERROR, unable to WriteMsg:", err)
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- break
|
|
|
+ for _, mode := range modes {
|
|
|
+ mode = strings.TrimSpace(mode)
|
|
|
+ sec, err := cfg.GetSection("log." + mode)
|
|
|
+ if err != nil {
|
|
|
+ rootLogger.Error("Unknown log mode", "mode", mode)
|
|
|
}
|
|
|
- }
|
|
|
- for _, l := range l.outputs {
|
|
|
- l.Flush()
|
|
|
- l.Destroy()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func (l *Logger) Trace(format string, v ...interface{}) {
|
|
|
- if l.level > TRACE {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[T] "+format, v...)
|
|
|
- l.writerMsg(0, TRACE, msg)
|
|
|
-}
|
|
|
-
|
|
|
-func (l *Logger) Debug(format string, v ...interface{}) {
|
|
|
- if l.level > DEBUG {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[D] "+format, v...)
|
|
|
- l.writerMsg(0, DEBUG, msg)
|
|
|
-}
|
|
|
-
|
|
|
-func (l *Logger) Info(format string, v ...interface{}) {
|
|
|
- if l.level > INFO {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[I] "+format, v...)
|
|
|
- l.writerMsg(0, INFO, msg)
|
|
|
-}
|
|
|
-
|
|
|
-func (l *Logger) Warn(format string, v ...interface{}) {
|
|
|
- if l.level > WARN {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[W] "+format, v...)
|
|
|
- l.writerMsg(0, WARN, msg)
|
|
|
-}
|
|
|
-
|
|
|
-func (l *Logger) Error(skip int, format string, v ...interface{}) {
|
|
|
- if l.level > ERROR {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[E] "+format, v...)
|
|
|
- l.writerMsg(skip, ERROR, msg)
|
|
|
-}
|
|
|
|
|
|
-func (l *Logger) Critical(skip int, format string, v ...interface{}) {
|
|
|
- if l.level > CRITICAL {
|
|
|
- return
|
|
|
+ // Log level.
|
|
|
+ _, level := getLogLevel("log."+mode, defaultLevelName, cfg)
|
|
|
+
|
|
|
+ // Generate log configuration.
|
|
|
+ switch mode {
|
|
|
+ case "console":
|
|
|
+ handlers = append(handlers, log15.LvlFilterHandler(level, log15.StdoutHandler))
|
|
|
+ case "file":
|
|
|
+ fileName := sec.Key("file_name").MustString(filepath.Join(logsPath, "grafana.log"))
|
|
|
+ os.MkdirAll(filepath.Dir(fileName), os.ModePerm)
|
|
|
+ fileHandler := NewFileWriter()
|
|
|
+ fileHandler.Filename = fileName
|
|
|
+ fileHandler.Rotate = sec.Key("log_rotate").MustBool(true)
|
|
|
+ fileHandler.Maxlines = sec.Key("max_lines").MustInt(1000000)
|
|
|
+ fileHandler.Maxsize = 1 << uint(sec.Key("max_size_shift").MustInt(28))
|
|
|
+ fileHandler.Daily = sec.Key("daily_rotate").MustBool(true)
|
|
|
+ fileHandler.Maxdays = sec.Key("max_days").MustInt64(7)
|
|
|
+ fileHandler.Init()
|
|
|
+
|
|
|
+ loggersToClose = append(loggersToClose, fileHandler)
|
|
|
+ handlers = append(handlers, log15.LazyHandler(fileHandler))
|
|
|
+
|
|
|
+ // case "conn":
|
|
|
+ // LogConfigs[i] = util.DynMap{
|
|
|
+ // "level": level,
|
|
|
+ // "reconnectOnMsg": sec.Key("reconnect_on_msg").MustBool(),
|
|
|
+ // "reconnect": sec.Key("reconnect").MustBool(),
|
|
|
+ // "net": sec.Key("protocol").In("tcp", []string{"tcp", "unix", "udp"}),
|
|
|
+ // "addr": sec.Key("addr").MustString(":7020"),
|
|
|
+ // }
|
|
|
+ // case "smtp":
|
|
|
+ // LogConfigs[i] = util.DynMap{
|
|
|
+ // "level": level,
|
|
|
+ // "user": sec.Key("user").MustString("example@example.com"),
|
|
|
+ // "passwd": sec.Key("passwd").MustString("******"),
|
|
|
+ // "host": sec.Key("host").MustString("127.0.0.1:25"),
|
|
|
+ // "receivers": sec.Key("receivers").MustString("[]"),
|
|
|
+ // "subject": sec.Key("subject").MustString("Diagnostic message from serve"),
|
|
|
+ // }
|
|
|
+ // case "database":
|
|
|
+ // LogConfigs[i] = util.DynMap{
|
|
|
+ // "level": level,
|
|
|
+ // "driver": sec.Key("driver").String(),
|
|
|
+ // "conn": sec.Key("conn").String(),
|
|
|
+ // }
|
|
|
+ // case "syslog":
|
|
|
+ // LogConfigs[i] = util.DynMap{
|
|
|
+ // "level": level,
|
|
|
+ // "network": sec.Key("network").MustString(""),
|
|
|
+ // "address": sec.Key("address").MustString(""),
|
|
|
+ // "facility": sec.Key("facility").MustString("local7"),
|
|
|
+ // "tag": sec.Key("tag").MustString(""),
|
|
|
+ // }
|
|
|
+ }
|
|
|
}
|
|
|
- msg := fmt.Sprintf("[C] "+format, v...)
|
|
|
- l.writerMsg(skip, CRITICAL, msg)
|
|
|
-}
|
|
|
|
|
|
-func (l *Logger) Fatal(skip int, format string, v ...interface{}) {
|
|
|
- if l.level > FATAL {
|
|
|
- return
|
|
|
- }
|
|
|
- msg := fmt.Sprintf("[F] "+format, v...)
|
|
|
- l.writerMsg(skip, FATAL, msg)
|
|
|
- l.Close()
|
|
|
- os.Exit(1)
|
|
|
+ rootLogger.SetHandler(log15.MultiHandler(handlers...))
|
|
|
}
|