1 package logrus_test
2
3 import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "sync"
8 "testing"
9
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12
13 . "github.com/sirupsen/logrus"
14 "github.com/sirupsen/logrus/hooks/test"
15 . "github.com/sirupsen/logrus/internal/testutils"
16 )
17
18 type TestHook struct {
19 Fired bool
20 }
21
22 func (hook *TestHook) Fire(entry *Entry) error {
23 hook.Fired = true
24 return nil
25 }
26
27 func (hook *TestHook) Levels() []Level {
28 return []Level{
29 TraceLevel,
30 DebugLevel,
31 InfoLevel,
32 WarnLevel,
33 ErrorLevel,
34 FatalLevel,
35 PanicLevel,
36 }
37 }
38
39 func TestHookFires(t *testing.T) {
40 hook := new(TestHook)
41
42 LogAndAssertJSON(t, func(log *Logger) {
43 log.Hooks.Add(hook)
44 assert.Equal(t, hook.Fired, false)
45
46 log.Print("test")
47 }, func(fields Fields) {
48 assert.Equal(t, hook.Fired, true)
49 })
50 }
51
52 type ModifyHook struct {
53 }
54
55 func (hook *ModifyHook) Fire(entry *Entry) error {
56 entry.Data["wow"] = "whale"
57 return nil
58 }
59
60 func (hook *ModifyHook) Levels() []Level {
61 return []Level{
62 TraceLevel,
63 DebugLevel,
64 InfoLevel,
65 WarnLevel,
66 ErrorLevel,
67 FatalLevel,
68 PanicLevel,
69 }
70 }
71
72 func TestHookCanModifyEntry(t *testing.T) {
73 hook := new(ModifyHook)
74
75 LogAndAssertJSON(t, func(log *Logger) {
76 log.Hooks.Add(hook)
77 log.WithField("wow", "elephant").Print("test")
78 }, func(fields Fields) {
79 assert.Equal(t, fields["wow"], "whale")
80 })
81 }
82
83 func TestCanFireMultipleHooks(t *testing.T) {
84 hook1 := new(ModifyHook)
85 hook2 := new(TestHook)
86
87 LogAndAssertJSON(t, func(log *Logger) {
88 log.Hooks.Add(hook1)
89 log.Hooks.Add(hook2)
90
91 log.WithField("wow", "elephant").Print("test")
92 }, func(fields Fields) {
93 assert.Equal(t, fields["wow"], "whale")
94 assert.Equal(t, hook2.Fired, true)
95 })
96 }
97
98 type SingleLevelModifyHook struct {
99 ModifyHook
100 }
101
102 func (h *SingleLevelModifyHook) Levels() []Level {
103 return []Level{InfoLevel}
104 }
105
106 func TestHookEntryIsPristine(t *testing.T) {
107 l := New()
108 b := &bytes.Buffer{}
109 l.Formatter = &JSONFormatter{}
110 l.Out = b
111 l.AddHook(&SingleLevelModifyHook{})
112
113 l.Error("error message")
114 data := map[string]string{}
115 err := json.Unmarshal(b.Bytes(), &data)
116 require.NoError(t, err)
117 _, ok := data["wow"]
118 require.False(t, ok)
119 b.Reset()
120
121 l.Info("error message")
122 data = map[string]string{}
123 err = json.Unmarshal(b.Bytes(), &data)
124 require.NoError(t, err)
125 _, ok = data["wow"]
126 require.True(t, ok)
127 b.Reset()
128
129 l.Error("error message")
130 data = map[string]string{}
131 err = json.Unmarshal(b.Bytes(), &data)
132 require.NoError(t, err)
133 _, ok = data["wow"]
134 require.False(t, ok)
135 b.Reset()
136 }
137
138 type ErrorHook struct {
139 Fired bool
140 }
141
142 func (hook *ErrorHook) Fire(entry *Entry) error {
143 hook.Fired = true
144 return nil
145 }
146
147 func (hook *ErrorHook) Levels() []Level {
148 return []Level{
149 ErrorLevel,
150 }
151 }
152
153 func TestErrorHookShouldntFireOnInfo(t *testing.T) {
154 hook := new(ErrorHook)
155
156 LogAndAssertJSON(t, func(log *Logger) {
157 log.Hooks.Add(hook)
158 log.Info("test")
159 }, func(fields Fields) {
160 assert.Equal(t, hook.Fired, false)
161 })
162 }
163
164 func TestErrorHookShouldFireOnError(t *testing.T) {
165 hook := new(ErrorHook)
166
167 LogAndAssertJSON(t, func(log *Logger) {
168 log.Hooks.Add(hook)
169 log.Error("test")
170 }, func(fields Fields) {
171 assert.Equal(t, hook.Fired, true)
172 })
173 }
174
175 func TestAddHookRace(t *testing.T) {
176 var wg sync.WaitGroup
177 wg.Add(2)
178 hook := new(ErrorHook)
179 LogAndAssertJSON(t, func(log *Logger) {
180 go func() {
181 defer wg.Done()
182 log.AddHook(hook)
183 }()
184 go func() {
185 defer wg.Done()
186 log.Error("test")
187 }()
188 wg.Wait()
189 }, func(fields Fields) {
190
191
192
193 })
194 }
195
196 func TestAddHookRace2(t *testing.T) {
197 t.Parallel()
198
199 for i := 0; i < 3; i++ {
200 testname := fmt.Sprintf("Test %d", i)
201 t.Run(testname, func(t *testing.T) {
202 t.Parallel()
203
204 _ = test.NewGlobal()
205 Info(testname)
206 })
207 }
208 }
209
210 type HookCallFunc struct {
211 F func()
212 }
213
214 func (h *HookCallFunc) Levels() []Level {
215 return AllLevels
216 }
217
218 func (h *HookCallFunc) Fire(e *Entry) error {
219 h.F()
220 return nil
221 }
222
223 func TestHookFireOrder(t *testing.T) {
224 checkers := []string{}
225 h := LevelHooks{}
226 h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "first hook") }})
227 h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "second hook") }})
228 h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "third hook") }})
229
230 if err := h.Fire(InfoLevel, &Entry{}); err != nil {
231 t.Error("unexpected error:", err)
232 }
233 require.Equal(t, []string{"first hook", "second hook", "third hook"}, checkers)
234 }
235
View as plain text