Hooks extend Logrus functionality by executing custom logic when logging at specific levels. Use hooks to send errors to tracking services, aggregate metrics, write to multiple outputs, or perform any custom action on log events.
Implement the Hook interface to create custom hooks.
type Hook interface {
Levels() []Level
Fire(*Entry) error
}The Levels() method returns which log levels trigger the hook. The Fire() method is called when a log entry matches one of those levels.
Add hooks to a logger instance:
func (logger *Logger) AddHook(hook Hook)
func AddHook(hook Hook) // Adds to standard loggerHooks are internally stored in a LevelHooks map.
type LevelHooks map[Level][]Hook
func (hooks LevelHooks) Add(hook Hook)
func (hooks LevelHooks) Fire(level Level, entry *Entry) errorAccess hooks directly:
log := logrus.New()
log.Hooks.Add(myHook)Replace all hooks:
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooksimport (
"errors"
log "github.com/sirupsen/logrus"
)
// ErrorHook sends errors to an error tracking service
type ErrorHook struct {
// Hook fields
}
func (hook *ErrorHook) Levels() []log.Level {
return []log.Level{
log.ErrorLevel,
log.FatalLevel,
log.PanicLevel,
}
}
func (hook *ErrorHook) Fire(entry *log.Entry) error {
// Send to error tracking service
// Return error if hook fails (will be logged to ErrorKey field)
return nil
}
func main() {
log.AddHook(&ErrorHook{})
log.Error("This will trigger the hook")
}Logrus provides several built-in hooks in the hooks package.
Package: github.com/sirupsen/logrus/hooks/syslog
Send logs to syslog daemon via network or Unix socket.
import "github.com/sirupsen/logrus/hooks/syslog"
import "log/syslog"
type SyslogHook struct {
Writer *syslog.Writer
SyslogNetwork string
SyslogRaddr string
}
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error)
func (hook *SyslogHook) Fire(entry *logrus.Entry) error
func (hook *SyslogHook) Levels() []logrus.Levelimport (
"log/syslog"
log "github.com/sirupsen/logrus"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
)
func main() {
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "myapp")
if err != nil {
log.Fatal(err)
}
log.AddHook(hook)
log.Info("This will be sent to syslog")
}Package: github.com/sirupsen/logrus/hooks/test
Capture log entries during testing for assertion and inspection.
import "github.com/sirupsen/logrus/hooks/test"
type Hook struct {
Entries []logrus.Entry // Use AllEntries() for safe access
// Has unexported fields
}
func NewGlobal() *Hook
func NewLocal(logger *logrus.Logger) *Hook
func NewNullLogger() (*logrus.Logger, *Hook)
func (t *Hook) Fire(e *logrus.Entry) error
func (t *Hook) Levels() []logrus.Level
func (t *Hook) AllEntries() []*logrus.Entry
func (t *Hook) LastEntry() *logrus.Entry
func (t *Hook) Reset()import (
"testing"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
)
func TestLogging(t *testing.T) {
logger, hook := test.NewNullLogger()
logger.Info("Test message")
logger.WithField("key", "value").Error("Test error")
assert.Equal(t, 2, len(hook.AllEntries()))
assert.Equal(t, "Test message", hook.AllEntries()[0].Message)
assert.Equal(t, log.InfoLevel, hook.AllEntries()[0].Level)
assert.Equal(t, "Test error", hook.LastEntry().Message)
assert.Equal(t, "value", hook.LastEntry().Data["key"])
hook.Reset()
assert.Equal(t, 0, len(hook.AllEntries()))
}Test hook with global logger:
import (
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
)
func TestWithGlobalLogger(t *testing.T) {
hook := test.NewGlobal()
log.Info("Using global logger")
assert.Equal(t, 1, len(hook.AllEntries()))
assert.Equal(t, "Using global logger", hook.LastEntry().Message)
}Test hook with specific logger:
import (
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
)
func TestWithLocalLogger(t *testing.T) {
logger := log.New()
hook := test.NewLocal(logger)
logger.Warn("Warning message")
assert.Equal(t, log.WarnLevel, hook.LastEntry().Level)
}Package: github.com/sirupsen/logrus/hooks/writer
Write specific log levels to different io.Writer destinations.
import "github.com/sirupsen/logrus/hooks/writer"
import "io"
type Hook struct {
Writer io.Writer
LogLevels []log.Level
}
func (hook *Hook) Fire(entry *log.Entry) error
func (hook *Hook) Levels() []log.Levelimport (
"os"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/writer"
)
func main() {
logger := log.New()
// Send Info and Debug to stdout
logger.AddHook(&writer.Hook{
Writer: os.Stdout,
LogLevels: []log.Level{
log.InfoLevel,
log.DebugLevel,
},
})
// Send Error, Fatal, Panic to stderr
logger.AddHook(&writer.Hook{
Writer: os.Stderr,
LogLevels: []log.Level{
log.ErrorLevel,
log.FatalLevel,
log.PanicLevel,
},
})
logger.Info("Goes to stdout")
logger.Error("Goes to stderr")
}Write to file:
import (
"os"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/writer"
)
func main() {
logger := log.New()
errorFile, err := os.OpenFile("errors.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer errorFile.Close()
logger.AddHook(&writer.Hook{
Writer: errorFile,
LogLevels: []log.Level{
log.ErrorLevel,
log.FatalLevel,
log.PanicLevel,
},
})
logger.Error("This goes to errors.log")
}Fire() to log hook failures