From 87e98f01cd3876a785f1888b4899a15eac46fdbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 8 Jun 2016 08:09:29 +0200 Subject: [PATCH] feat(logging): updated syslog writer to work with log15 log interface, closes #4590 --- CHANGELOG.md | 4 ++ pkg/log/log.go | 25 +++---- pkg/log/syslog.go | 177 ++++++++++++++++++++++------------------------ 3 files changed, 102 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b6371b324..6c94d5032d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * **Theme**: Add default theme to config file [#5011](https://github.com/grafana/grafana/pull/5011) * **Page Footer**: Added page footer with links to docs, shows Grafana version and info if new version is available, closes [#4889](https://github.com/grafana/grafana/pull/4889) * **InfluxDB**: Add spread function, closes [#5211](https://github.com/grafana/grafana/issues/5211) +* **Logging**: Moved to structured logging lib, and moved to component specific level filters via config file, closes [#4590](https://github.com/grafana/grafana/issues/4590) + +## Breaking changes +* **Logging** : Changed default logging output format (now structured into message, and key value pairs, with logger key acting as component). You can also no change in config to json log ouput. # 3.0.4 Patch release (2016-05-25) * **Panel**: Fixed blank dashboard issue when switching to other dashboard while in fullscreen edit mode, fixes [#5163](https://github.com/grafana/grafana/pull/5163) diff --git a/pkg/log/log.go b/pkg/log/log.go index 6e75a2b9a8c..f4865169e95 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -157,15 +157,20 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { loggersToClose = append(loggersToClose, fileHandler) handler = fileHandler + case "syslog": + sysLogHandler := NewSyslog() + sysLogHandler.Network = sec.Key("network").MustString("") + sysLogHandler.Address = sec.Key("address").MustString("") + sysLogHandler.Facility = sec.Key("facility").MustString("local7") + sysLogHandler.Tag = sec.Key("tag").MustString("") - // 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(""), - // } + if err := sysLogHandler.Init(); err != nil { + Root.Error("Failed to init syslog log handler", "error", err) + os.Exit(1) + } + + loggersToClose = append(loggersToClose, sysLogHandler) + handler = sysLogHandler } for key, value := range defaultFilters { @@ -174,10 +179,6 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { } } - for key, value := range modeFilters { - fmt.Printf("key: %v, value: %v \n", key, value) - } - handler = LogFilterHandler(level, modeFilters, handler) handlers = append(handlers, handler) } diff --git a/pkg/log/syslog.go b/pkg/log/syslog.go index cdf03555238..29a22e9fe1e 100644 --- a/pkg/log/syslog.go +++ b/pkg/log/syslog.go @@ -2,95 +2,88 @@ package log -// -// import ( -// "encoding/json" -// "errors" -// "log/syslog" -// ) -// -// type SyslogWriter struct { -// syslog *syslog.Writer -// Network string `json:"network"` -// Address string `json:"address"` -// Facility string `json:"facility"` -// Tag string `json:"tag"` -// } -// -// func NewSyslog() LoggerInterface { -// return new(SyslogWriter) -// } -// -// func (sw *SyslogWriter) Init(config string) error { -// if err := json.Unmarshal([]byte(config), sw); err != nil { -// return err -// } -// -// prio, err := parseFacility(sw.Facility) -// if err != nil { -// return err -// } -// -// w, err := syslog.Dial(sw.Network, sw.Address, prio, sw.Tag) -// if err != nil { -// return err -// } -// -// sw.syslog = w -// return nil -// } -// -// func (sw *SyslogWriter) WriteMsg(msg string, skip int, level LogLevel) error { -// var err error -// -// switch level { -// case TRACE, DEBUG: -// err = sw.syslog.Debug(msg) -// case INFO: -// err = sw.syslog.Info(msg) -// case WARN: -// err = sw.syslog.Warning(msg) -// case ERROR: -// err = sw.syslog.Err(msg) -// case CRITICAL: -// err = sw.syslog.Crit(msg) -// case FATAL: -// err = sw.syslog.Alert(msg) -// default: -// err = errors.New("invalid syslog level") -// } -// -// return err -// } -// -// func (sw *SyslogWriter) Destroy() { -// sw.syslog.Close() -// } -// -// func (sw *SyslogWriter) Flush() {} -// -// var facilities = map[string]syslog.Priority{ -// "user": syslog.LOG_USER, -// "daemon": syslog.LOG_DAEMON, -// "local0": syslog.LOG_LOCAL0, -// "local1": syslog.LOG_LOCAL1, -// "local2": syslog.LOG_LOCAL2, -// "local3": syslog.LOG_LOCAL3, -// "local4": syslog.LOG_LOCAL4, -// "local5": syslog.LOG_LOCAL5, -// "local6": syslog.LOG_LOCAL6, -// "local7": syslog.LOG_LOCAL7, -// } -// -// func parseFacility(facility string) (syslog.Priority, error) { -// prio, ok := facilities[facility] -// if !ok { -// return syslog.LOG_LOCAL0, errors.New("invalid syslog facility") -// } -// -// return prio, nil -// } -// -// func init() { -// Register("syslog", NewSyslog) -// } +import ( + "errors" + "log/syslog" + + "github.com/inconshreveable/log15" +) + +type SysLogHandler struct { + syslog *syslog.Writer + Network string + Address string + Facility string + Tag string + Format log15.Format +} + +func NewSyslog() *SysLogHandler { + return &SysLogHandler{ + Format: log15.LogfmtFormat(), + } +} + +func (sw *SysLogHandler) Init() error { + prio, err := parseFacility(sw.Facility) + if err != nil { + return err + } + + w, err := syslog.Dial(sw.Network, sw.Address, prio, sw.Tag) + if err != nil { + return err + } + + sw.syslog = w + return nil +} + +func (sw *SysLogHandler) Log(r *log15.Record) error { + var err error + + msg := string(sw.Format.Format(r)) + + switch r.Lvl { + case log15.LvlDebug: + err = sw.syslog.Debug(msg) + case log15.LvlInfo: + err = sw.syslog.Info(msg) + case log15.LvlWarn: + err = sw.syslog.Warning(msg) + case log15.LvlError: + err = sw.syslog.Err(msg) + case log15.LvlCrit: + err = sw.syslog.Crit(msg) + default: + err = errors.New("invalid syslog level") + } + + return err +} + +func (sw *SysLogHandler) Close() { + sw.syslog.Close() +} + +var facilities = map[string]syslog.Priority{ + "user": syslog.LOG_USER, + "daemon": syslog.LOG_DAEMON, + "local0": syslog.LOG_LOCAL0, + "local1": syslog.LOG_LOCAL1, + "local2": syslog.LOG_LOCAL2, + "local3": syslog.LOG_LOCAL3, + "local4": syslog.LOG_LOCAL4, + "local5": syslog.LOG_LOCAL5, + "local6": syslog.LOG_LOCAL6, + "local7": syslog.LOG_LOCAL7, +} + +func parseFacility(facility string) (syslog.Priority, error) { + prio, ok := facilities[facility] + if !ok { + return syslog.LOG_LOCAL0, errors.New("invalid syslog facility") + } + + return prio, nil +}