From d8e3add56fa5b0b0c7f4917554f16ac93a1ff90a Mon Sep 17 00:00:00 2001 From: tbunyk Date: Fri, 15 Mar 2019 13:09:11 +0200 Subject: [PATCH] Add hook to send logs to custom writer #678 --- hooks/writer/README.md | 43 +++++++++++++++++++++++++++++++++++++ hooks/writer/writer.go | 29 +++++++++++++++++++++++++ hooks/writer/writer_test.go | 37 +++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 hooks/writer/README.md create mode 100644 hooks/writer/writer.go create mode 100644 hooks/writer/writer_test.go diff --git a/hooks/writer/README.md b/hooks/writer/README.md new file mode 100644 index 0000000..6967630 --- /dev/null +++ b/hooks/writer/README.md @@ -0,0 +1,43 @@ +# Writer Hooks for Logrus + +Send logs of given levels to any object with `io.Writer` interface. + +## Usage + +If you want for example send high level logs to `Stderr` and +logs of normal execution to `Stdout`, you could do it like this: + +```go +package main + +import ( + "io/ioutil" + "os" + + log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/writer" +) + +func main() { + log.SetOutput(ioutil.Discard) // Send all logs to nowhere by default + + log.AddHook(&writer.Hook{ // Send logs with level higher than warning to stderr + Writer: os.Stderr, + LogLevels: []log.Level{ + log.PanicLevel, + log.FatalLevel, + log.ErrorLevel, + log.WarnLevel, + }, + }) + log.AddHook(&writer.Hook{ // Send info and debug logs to stdout + Writer: os.Stdout, + LogLevels: []log.Level{ + log.InfoLevel, + log.DebugLevel, + }, + }) + log.Info("This will go to stdout") + log.Warn("This will go to stderr") +} +``` diff --git a/hooks/writer/writer.go b/hooks/writer/writer.go new file mode 100644 index 0000000..0532dee --- /dev/null +++ b/hooks/writer/writer.go @@ -0,0 +1,29 @@ +package writer + +import ( + "io" + + log "github.com/sirupsen/logrus" +) + +// Hook is a hook that writes logs of specified LogLevels to specified Writer +type Hook struct { + Writer io.Writer + LogLevels []log.Level +} + +// Fire will be called when some logging function is called with current hook +// It will format log entry to string and write it to appropriate writer +func (hook *Hook) Fire(entry *log.Entry) error { + line, err := entry.String() + if err != nil { + return err + } + _, err = hook.Writer.Write([]byte(line)) + return err +} + +// Levels define on which log levels this hook would trigger +func (hook *Hook) Levels() []log.Level { + return hook.LogLevels +} diff --git a/hooks/writer/writer_test.go b/hooks/writer/writer_test.go new file mode 100644 index 0000000..22cfdff --- /dev/null +++ b/hooks/writer/writer_test.go @@ -0,0 +1,37 @@ +package writer + +import ( + "bytes" + "io/ioutil" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestDifferentLevelsGoToDifferentWriters(t *testing.T) { + var a, b bytes.Buffer + + log.SetFormatter(&log.TextFormatter{ + DisableTimestamp: true, + }) + log.SetOutput(ioutil.Discard) // Send all logs to nowhere by default + + log.AddHook(&Hook{ + Writer: &a, + LogLevels: []log.Level{ + log.WarnLevel, + }, + }) + log.AddHook(&Hook{ // Send info and debug logs to stdout + Writer: &b, + LogLevels: []log.Level{ + log.InfoLevel, + }, + }) + log.Warn("send to a") + log.Info("send to b") + + assert.Equal(t, a.String(), "level=warning msg=\"send to a\"\n") + assert.Equal(t, b.String(), "level=info msg=\"send to b\"\n") +}