Add systemlog hook

Signed-off-by: Maxim Zakharov <dp.maxime@gmail.com>
This commit is contained in:
Maxim Zakharov 2019-01-10 15:01:09 +11:00
parent eef6b768ab
commit 0602c483e7
6 changed files with 254 additions and 0 deletions

57
hooks/systemlog/README.md Normal file
View File

@ -0,0 +1,57 @@
# System log Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
## Usage
```go
import (
"log/syslog"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/systemlog"
)
func main() {
log := logrus.New()
hook, err := systemlog.NewSystemlogHook("udp", "localhost:514", "")
if err == nil {
log.Hooks.Add(hook)
}
}
```
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSystemlogHook`. It should look like the following.
```go
import (
"log/syslog"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/systemlog"
)
func main() {
log := logrus.New()
hook, err := systemlog.NewSyslogHook("", "", "")
if err == nil {
log.Hooks.Add(hook)
}
}
```
On Windows it connects to event log. You may use third parameter to specify your event source.
```go
import (
"log/syslog"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/systemlog"
)
func main() {
log := logrus.New()
hook, err := systemlog.NewSyslogHook("", "localhost", "MySource")
if err == nil {
log.Hooks.Add(hook)
}
}
```

View File

@ -0,0 +1,27 @@
// +build nacl
// FIX IT: this is a stub to allow build on nacl.
// Need to be implemented according nacl system facilities.
package systemlog
import (
"github.com/sirupsen/logrus"
)
// SystemlogHook to do nothing on syslogless systems.
type SystemlogHook struct {
}
// Creates a stub hook to be added to an instance of logger on syslogless systems.
func NewSystemlogHook(network, raddr string, tag string) (*SystemlogHook, error) {
return &SystemlogHook{}, nil
}
func (hook *SystemlogHook) Fire(entry *logrus.Entry) error {
return nil
}
func (hook *SystemlogHook) Levels() []logrus.Level {
return make([]logrus.Level, 0, 0)
}

View File

@ -0,0 +1,27 @@
// +build plan9
// FIX IT: this is a stub to allow build on plan9.
// Need to be implemented according plan9 system facilities.
package lachesis_log
import (
"github.com/sirupsen/logrus"
)
// SystemlogHook to do nothing on syslogless systems.
type SystemlogHook struct {
}
// Creates a stub hook to be added to an instance of logger on syslogless systems.
func NewSystemlogHook(network, raddr string, tag string) (*SystemlogHook, error) {
return &SystemlogHook{}, nil
}
func (hook *SystemlogHook) Fire(entry *logrus.Entry) error {
return nil
}
func (hook *SystemlogHook) Levels() []logrus.Level {
return make([]logrus.Level, 0, 0)
}

View File

@ -0,0 +1,26 @@
package systemlog
import (
"testing"
"github.com/sirupsen/logrus"
)
func TestLocalhostAddAndPrint(t *testing.T) {
log := logrus.New()
hook, err := NewSystemlogHook("udp", "localhost:514", "systemlog-test")
if err != nil {
t.Errorf("Unable to connect to local syslog.")
}
log.Hooks.Add(hook)
for _, level := range hook.Levels() {
if len(log.Hooks[level]) != 1 {
t.Errorf("SystemlogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
}
}
log.Info("Congratulations!")
}

View File

@ -0,0 +1,53 @@
// +build !windows,!nacl,!plan9
package systemlog
import (
"fmt"
"log/syslog"
"os"
"github.com/sirupsen/logrus"
)
// SystemlogHook to send logs via syslog.
type SystemlogHook struct {
Writer *syslog.Writer
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := NewSystemlogHook("udp", "localhost:514", "")`
// `if err == nil { log.Hooks.Add(hook) }`
func NewSystemlogHook(network, raddr string, tag string) (*SystemlogHook, error) {
w, err := syslog.Dial(network, raddr, syslog.LOG_INFO, tag)
return &SystemlogHook{w,}, err
}
func (hook *SystemlogHook) Fire(entry *logrus.Entry) 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
}
}
func (hook *SystemlogHook) Levels() []logrus.Level {
return logrus.AllLevels
}

View File

@ -0,0 +1,64 @@
// +build windows
package systemlog
import (
"fmt"
"strings"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc/eventlog"
"github.com/sirupsen/logrus"
)
// SystemlogHook to send logs via syslog.
type SystemlogHook struct {
Writer *eventlog.Log
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := NewSystemlogHook("", "localhost", "MySource")`
// `if err == nil { log.Hooks.Add(hook) }`
func NewSystemlogHook(network, raddr string, src string) (*SystemlogHook, error) {
// Continue if we receive "registry key already exists" or if we get
// ERROR_ACCESS_DENIED so that we can log without administrative permissions
// for pre-existing eventlog sources.
if err := eventlog.InstallAsEventCreate(src, eventlog.Info|eventlog.Warning|eventlog.Error); err != nil {
if !strings.Contains(err.Error(), "registry key already exists") && err != windows.ERROR_ACCESS_DENIED {
return nil, err
}
}
el, err := eventlog.OpenRemote(raddr, src)
if err != nil {
return nil, err
}
return &SystemlogHook{el,}, err
}
func (hook *SystemlogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
return fmt.Errorf("Unable to read entry, %v", err)
}
switch entry.Level {
case logrus.PanicLevel:
return hook.Writer.Error(1, line)
case logrus.FatalLevel:
return hook.Writer.Error(2, line)
case logrus.ErrorLevel:
return hook.Writer.Error(3, line)
case logrus.WarnLevel:
return hook.Writer.Warning(4, line)
case logrus.InfoLevel:
return hook.Writer.Info(5, line)
case logrus.DebugLevel, logrus.TraceLevel:
return hook.Writer.Info(6, line)
default:
return nil
}
}
func (hook *SystemlogHook) Levels() []logrus.Level {
return logrus.AllLevels
}