feat(logging): a lot of progress on moving to new logging lib, #4590

This commit is contained in:
Torkel Ödegaard
2016-06-06 23:06:44 +02:00
parent 25899b72d2
commit 22778e6efd
18 changed files with 314 additions and 707 deletions
+113 -270
View File
@@ -8,324 +8,167 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
"gopkg.in/ini.v1"
"github.com/inconshreveable/log15"
)
var (
loggers []*Logger
)
var rootLogger log15.Logger
var loggersToClose []DisposableHandler
func NewLogger(bufLen int64, mode, config string) {
logger := newLogger(bufLen)
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 Debug2(message string, v ...interface{}) {
rootLogger.Debug(message, v...)
}
func Info(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Info(format, v...)
}
rootLogger.Info(fmt.Sprintf(format, v))
}
func Info2(message string, v ...interface{}) {
rootLogger.Info(message, v...)
}
func Warn(format string, v ...interface{}) {
for _, logger := range loggers {
logger.Warn(format, v...)
}
rootLogger.Warn(fmt.Sprintf(format, v))
}
func Warn2(message string, v ...interface{}) {
rootLogger.Warn(message, v...)
}
func Error(skip int, format string, v ...interface{}) {
for _, logger := range loggers {
logger.Error(skip, format, v...)
}
rootLogger.Error(fmt.Sprintf(format, v))
}
func Error2(message string, v ...interface{}) {
rootLogger.Error(message, v...)
}
func Critical(skip int, format string, v ...interface{}) {
for _, logger := range loggers {
logger.Critical(skip, format, v...)
}
rootLogger.Crit(fmt.Sprintf(format, v))
}
func Fatal(skip int, format string, v ...interface{}) {
Error(skip, format, v...)
for _, l := range loggers {
l.Close()
}
rootLogger.Crit(fmt.Sprintf(format, v))
Close()
os.Exit(1)
}
func Close() {
for _, l := range loggers {
l.Close()
// delete the logger.
l = nil
for _, logger := range loggersToClose {
logger.Close()
}
// clear the loggers slice.
loggers = nil
loggersToClose = make([]DisposableHandler, 0)
}
// .___ __ _____
// | | _____/ |_ ____________/ ____\____ ____ ____
// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \
// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/
// |___|___| /__| \___ >__| |__| (____ /\___ >___ >
// \/ \/ \/ \/ \/
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()
var logLevels = map[string]log15.Lvl{
"Trace": log15.LvlDebug,
"Debug": log15.LvlDebug,
"Info": log15.LvlInfo,
"Warn": log15.LvlWarn,
"Error": log15.LvlError,
"Critical": log15.LvlCrit,
}
type loggerType func() LoggerInterface
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"})
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")
level, ok := logLevels[levelName]
if !ok {
rootLogger.Error("Unknown log level", "level", levelName)
}
if _, dup := adapters[name]; dup {
panic("log: register called twice for provider \"" + name + "\"")
}
adapters[name] = log
return levelName, level
}
type logMsg struct {
skip int
level LogLevel
msg string
}
func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) {
Close()
// 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
}
defaultLevelName, _ := getLogLevel("log", "Info", cfg)
handlers := make([]log15.Handler, 0)
// 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),
}
go l.StartLogger()
return l
}
// 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
for _, mode := range modes {
mode = strings.TrimSpace(mode)
sec, err := cfg.GetSection("log." + mode)
if err != nil {
rootLogger.Error("Unknown log mode", "mode", mode)
}
l.outputs[adapter] = lg
l.adapter = adapter
} else {
panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)")
}
return nil
}
// 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
}
// Log level.
_, level := getLogLevel("log."+mode, defaultLevelName, cfg)
func (l *Logger) writerMsg(skip int, level LogLevel, msg string) error {
lm := &logMsg{
skip: skip,
level: level,
}
// 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()
// 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()), ".") + "()"
}
loggersToClose = append(loggersToClose, fileHandler)
handlers = append(handlers, log15.LazyHandler(fileHandler))
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
}
// 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
// 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(""),
// }
}
}
}
// Flush flushs all chan data.
func (l *Logger) Flush() {
for _, l := range l.outputs {
l.Flush()
}
}
// 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 _, 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
}
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...))
}