Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions hook_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package logrus_test

import (
"errors"
"fmt"
"io"
"maps"
Expand Down Expand Up @@ -259,3 +260,33 @@ func TestHookFireOrder(t *testing.T) {
}
require.Equal(t, []string{"first hook", "second hook", "third hook"}, checkers)
}

type errHook struct {
name string
err error
hit *[]string
}

func (h *errHook) Levels() []Level { return AllLevels }

func (h *errHook) Fire(*Entry) error {
if h.hit != nil {
*h.hit = append(*h.hit, h.name)
}
return h.err
}

func TestHookFireContinuesAfterError(t *testing.T) {
// Issue #408: an error from one hook must not skip later hooks.
var hit []string
h := LevelHooks{}
h.Add(&errHook{name: "first", err: errors.New("boom-first"), hit: &hit})
h.Add(&errHook{name: "second", err: nil, hit: &hit})
h.Add(&errHook{name: "third", err: errors.New("boom-third"), hit: &hit})

err := h.Fire(InfoLevel, &Entry{})
require.Error(t, err)
require.ErrorContains(t, err, "boom-first")
require.ErrorContains(t, err, "boom-third")
require.Equal(t, []string{"first", "second", "third"}, hit)
}
12 changes: 9 additions & 3 deletions hooks.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package logrus

import "errors"

// Hook describes hooks to be fired when logging on the logging levels returned from
// [Hook.Levels] on your implementation of the interface. Note that this is not
// fired in a goroutine or a channel with workers, you should handle such
Expand All @@ -23,12 +25,16 @@ func (hooks LevelHooks) Add(hook Hook) {

// Fire all the hooks for the passed level. Used by `entry.log` to fire
// appropriate hooks for a log entry.
//
// Every hook for the level is invoked even if an earlier hook returns an
// error. When multiple hooks fail, the returned error is the join of all
// errors (Go 1.20+ errors.Join). This matches the doc comment: fire all hooks.
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
var errs []error
for _, hook := range hooks[level] {
if err := hook.Fire(entry); err != nil {
return err
errs = append(errs, err)
}
}

return nil
return errors.Join(errs...)
}
Loading