diff --git a/entry.go b/entry.go index 7f28ba4..263b005 100644 --- a/entry.go +++ b/entry.go @@ -85,10 +85,15 @@ func NewEntry(logger *Logger) *Entry { } } +// Returns the bytes representation of this entry from the formatter. +func (entry *Entry) Bytes() ([]byte, error) { + return entry.Logger.Formatter.Format(entry) +} + // Returns the string representation from the reader and ultimately the // formatter. func (entry *Entry) String() (string, error) { - serialized, err := entry.Logger.Formatter.Format(entry) + serialized, err := entry.Bytes() if err != nil { return "", err } 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..1160c79 --- /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.Bytes() + if err != nil { + return err + } + _, err = hook.Writer.Write(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..a30d3b0 --- /dev/null +++ b/hooks/writer/writer_test.go @@ -0,0 +1,38 @@ +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, + DisableColors: 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") +}