or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

formatters.mdhooks.mdindex.mdinterfaces.md
tile.json

hooks.mddocs/

Hooks

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.

Hook Interface

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.

Adding Hooks

Add hooks to a logger instance:

func (logger *Logger) AddHook(hook Hook)
func AddHook(hook Hook)  // Adds to standard logger

LevelHooks

Hooks 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) error

Access hooks directly:

log := logrus.New()
log.Hooks.Add(myHook)

Replace all hooks:

func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks

Custom Hook Example

import (
    "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")
}

Built-in Hooks

Logrus provides several built-in hooks in the hooks package.

Syslog Hook

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.Level

Syslog Hook Usage

import (
    "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")
}

Test Hook

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()

Test Hook Usage

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)
}

Writer Hook

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.Level

Writer Hook Usage

import (
    "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")
}

Hook Best Practices

  1. Non-blocking: Hooks fire synchronously. For expensive operations, use goroutines and channels
  2. Error handling: Return errors from Fire() to log hook failures
  3. Level selection: Only hook necessary levels to minimize overhead
  4. Thread safety: Ensure hook implementations are thread-safe
  5. Testing: Use test hooks to verify logging behavior in tests