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