From f160b155bbf102560c81fff57775175ebaa34441 Mon Sep 17 00:00:00 2001 From: aluvare Date: Thu, 11 Feb 2021 15:56:16 +0100 Subject: [PATCH] The syslog library has been changed to prevent crashes if the syslog server is down, writing does not degrade if syslog server is slow. --- hooks/syslog/syslog.go | 89 +++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/hooks/syslog/syslog.go b/hooks/syslog/syslog.go index 02b8df3..0d75516 100644 --- a/hooks/syslog/syslog.go +++ b/hooks/syslog/syslog.go @@ -4,50 +4,95 @@ package syslog import ( "fmt" - "log/syslog" + //"log/syslog" + "github.com/GolangResources/syslog/syslog" "os" + "time" "github.com/sirupsen/logrus" ) +const ( + NUM_SYSLOG_WORKERS = 8 + CHANNEL_DEPTH = 8192 +) + // SyslogHook to send logs via syslog. type SyslogHook struct { - Writer *syslog.Writer - SyslogNetwork string - SyslogRaddr string + Writer *syslog.Writer + SyslogNetwork string + SyslogRaddr string + Tag string + syschan chan *SEntry +} + +type SEntry struct { + line string + level logrus.Level } // Creates a hook to be added to an instance of logger. This is called with // `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` // `if err == nil { log.Hooks.Add(hook) }` func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { - w, err := syslog.Dial(network, raddr, priority, tag) - return &SyslogHook{w, network, raddr}, err + w, err := syslog.Dial("ctcp" , raddr, priority, nil) + if err != nil { + return nil, err + } + hook := &SyslogHook{ + w, + network, + raddr, + tag, + make(chan *SEntry, CHANNEL_DEPTH), + } + for i := 0; i <= NUM_SYSLOG_WORKERS; i++ { + go hook.worker(i) + } + return hook, err +} + +func (hook *SyslogHook) worker(i int) { + for entry := range hook.syschan { + time.Sleep(1) + func() error { + switch entry.level { + case logrus.PanicLevel: + return hook.Writer.Crit(&entry.line, hook.Tag) + case logrus.FatalLevel: + return hook.Writer.Crit(&entry.line, hook.Tag) + case logrus.ErrorLevel: + return hook.Writer.Err(&entry.line, hook.Tag) + case logrus.WarnLevel: + return hook.Writer.Warning(&entry.line, hook.Tag) + case logrus.InfoLevel: + return hook.Writer.Info(&entry.line, hook.Tag) + case logrus.DebugLevel, logrus.TraceLevel: + return hook.Writer.Debug(&entry.line, hook.Tag) + default: + return nil + } + }() + } } func (hook *SyslogHook) Fire(entry *logrus.Entry) error { + var err error line, err := entry.String() if err != nil { fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) return err } - - switch entry.Level { - case logrus.PanicLevel: - return hook.Writer.Crit(line) - case logrus.FatalLevel: - return hook.Writer.Crit(line) - case logrus.ErrorLevel: - return hook.Writer.Err(line) - case logrus.WarnLevel: - return hook.Writer.Warning(line) - case logrus.InfoLevel: - return hook.Writer.Info(line) - case logrus.DebugLevel, logrus.TraceLevel: - return hook.Writer.Debug(line) - default: - return nil + sentry := &SEntry{ + line: line, + level: entry.Level, } + select { + case hook.syschan <- sentry: + default: + err = fmt.Errorf("logrus syslog chan full") + } + return err } func (hook *SyslogHook) Levels() []logrus.Level {