1package logrus 2 3import ( 4 "bytes" 5 "context" 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11) 12 13func TestEntryWithError(t *testing.T) { 14 15 assert := assert.New(t) 16 17 defer func() { 18 ErrorKey = "error" 19 }() 20 21 err := fmt.Errorf("kaboom at layer %d", 4711) 22 23 assert.Equal(err, WithError(err).Data["error"]) 24 25 logger := New() 26 logger.Out = &bytes.Buffer{} 27 entry := NewEntry(logger) 28 29 assert.Equal(err, entry.WithError(err).Data["error"]) 30 31 ErrorKey = "err" 32 33 assert.Equal(err, entry.WithError(err).Data["err"]) 34 35} 36 37func TestEntryWithContext(t *testing.T) { 38 assert := assert.New(t) 39 ctx := context.WithValue(context.Background(), "foo", "bar") 40 41 assert.Equal(ctx, WithContext(ctx).Context) 42 43 logger := New() 44 logger.Out = &bytes.Buffer{} 45 entry := NewEntry(logger) 46 47 assert.Equal(ctx, entry.WithContext(ctx).Context) 48} 49 50func TestEntryWithContextCopiesData(t *testing.T) { 51 assert := assert.New(t) 52 53 // Initialize a parent Entry object with a key/value set in its Data map 54 logger := New() 55 logger.Out = &bytes.Buffer{} 56 parentEntry := NewEntry(logger).WithField("parentKey", "parentValue") 57 58 // Create two children Entry objects from the parent in different contexts 59 ctx1 := context.WithValue(context.Background(), "foo", "bar") 60 childEntry1 := parentEntry.WithContext(ctx1) 61 assert.Equal(ctx1, childEntry1.Context) 62 63 ctx2 := context.WithValue(context.Background(), "bar", "baz") 64 childEntry2 := parentEntry.WithContext(ctx2) 65 assert.Equal(ctx2, childEntry2.Context) 66 assert.NotEqual(ctx1, ctx2) 67 68 // Ensure that data set in the parent Entry are preserved to both children 69 assert.Equal("parentValue", childEntry1.Data["parentKey"]) 70 assert.Equal("parentValue", childEntry2.Data["parentKey"]) 71 72 // Modify data stored in the child entry 73 childEntry1.Data["childKey"] = "childValue" 74 75 // Verify that data is successfully stored in the child it was set on 76 val, exists := childEntry1.Data["childKey"] 77 assert.True(exists) 78 assert.Equal("childValue", val) 79 80 // Verify that the data change to child 1 has not affected its sibling 81 val, exists = childEntry2.Data["childKey"] 82 assert.False(exists) 83 assert.Empty(val) 84 85 // Verify that the data change to child 1 has not affected its parent 86 val, exists = parentEntry.Data["childKey"] 87 assert.False(exists) 88 assert.Empty(val) 89} 90 91func TestEntryWithTimeCopiesData(t *testing.T) { 92 assert := assert.New(t) 93 94 // Initialize a parent Entry object with a key/value set in its Data map 95 logger := New() 96 logger.Out = &bytes.Buffer{} 97 parentEntry := NewEntry(logger).WithField("parentKey", "parentValue") 98 99 // Create two children Entry objects from the parent with two different times 100 childEntry1 := parentEntry.WithTime(time.Now().AddDate(0, 0, 1)) 101 childEntry2 := parentEntry.WithTime(time.Now().AddDate(0, 0, 2)) 102 103 // Ensure that data set in the parent Entry are preserved to both children 104 assert.Equal("parentValue", childEntry1.Data["parentKey"]) 105 assert.Equal("parentValue", childEntry2.Data["parentKey"]) 106 107 // Modify data stored in the child entry 108 childEntry1.Data["childKey"] = "childValue" 109 110 // Verify that data is successfully stored in the child it was set on 111 val, exists := childEntry1.Data["childKey"] 112 assert.True(exists) 113 assert.Equal("childValue", val) 114 115 // Verify that the data change to child 1 has not affected its sibling 116 val, exists = childEntry2.Data["childKey"] 117 assert.False(exists) 118 assert.Empty(val) 119 120 // Verify that the data change to child 1 has not affected its parent 121 val, exists = parentEntry.Data["childKey"] 122 assert.False(exists) 123 assert.Empty(val) 124} 125 126func TestEntryPanicln(t *testing.T) { 127 errBoom := fmt.Errorf("boom time") 128 129 defer func() { 130 p := recover() 131 assert.NotNil(t, p) 132 133 switch pVal := p.(type) { 134 case *Entry: 135 assert.Equal(t, "kaboom", pVal.Message) 136 assert.Equal(t, errBoom, pVal.Data["err"]) 137 default: 138 t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 139 } 140 }() 141 142 logger := New() 143 logger.Out = &bytes.Buffer{} 144 entry := NewEntry(logger) 145 entry.WithField("err", errBoom).Panicln("kaboom") 146} 147 148func TestEntryPanicf(t *testing.T) { 149 errBoom := fmt.Errorf("boom again") 150 151 defer func() { 152 p := recover() 153 assert.NotNil(t, p) 154 155 switch pVal := p.(type) { 156 case *Entry: 157 assert.Equal(t, "kaboom true", pVal.Message) 158 assert.Equal(t, errBoom, pVal.Data["err"]) 159 default: 160 t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 161 } 162 }() 163 164 logger := New() 165 logger.Out = &bytes.Buffer{} 166 entry := NewEntry(logger) 167 entry.WithField("err", errBoom).Panicf("kaboom %v", true) 168} 169 170func TestEntryPanic(t *testing.T) { 171 errBoom := fmt.Errorf("boom again") 172 173 defer func() { 174 p := recover() 175 assert.NotNil(t, p) 176 177 switch pVal := p.(type) { 178 case *Entry: 179 assert.Equal(t, "kaboom", pVal.Message) 180 assert.Equal(t, errBoom, pVal.Data["err"]) 181 default: 182 t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 183 } 184 }() 185 186 logger := New() 187 logger.Out = &bytes.Buffer{} 188 entry := NewEntry(logger) 189 entry.WithField("err", errBoom).Panic("kaboom") 190} 191 192const ( 193 badMessage = "this is going to panic" 194 panicMessage = "this is broken" 195) 196 197type panickyHook struct{} 198 199func (p *panickyHook) Levels() []Level { 200 return []Level{InfoLevel} 201} 202 203func (p *panickyHook) Fire(entry *Entry) error { 204 if entry.Message == badMessage { 205 panic(panicMessage) 206 } 207 208 return nil 209} 210 211func TestEntryHooksPanic(t *testing.T) { 212 logger := New() 213 logger.Out = &bytes.Buffer{} 214 logger.Level = InfoLevel 215 logger.Hooks.Add(&panickyHook{}) 216 217 defer func() { 218 p := recover() 219 assert.NotNil(t, p) 220 assert.Equal(t, panicMessage, p) 221 222 entry := NewEntry(logger) 223 entry.Info("another message") 224 }() 225 226 entry := NewEntry(logger) 227 entry.Info(badMessage) 228} 229 230func TestEntryWithIncorrectField(t *testing.T) { 231 assert := assert.New(t) 232 233 fn := func() {} 234 235 e := Entry{Logger: New()} 236 eWithFunc := e.WithFields(Fields{"func": fn}) 237 eWithFuncPtr := e.WithFields(Fields{"funcPtr": &fn}) 238 239 assert.Equal(eWithFunc.err, `can not add field "func"`) 240 assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) 241 242 eWithFunc = eWithFunc.WithField("not_a_func", "it is a string") 243 eWithFuncPtr = eWithFuncPtr.WithField("not_a_func", "it is a string") 244 245 assert.Equal(eWithFunc.err, `can not add field "func"`) 246 assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) 247 248 eWithFunc = eWithFunc.WithTime(time.Now()) 249 eWithFuncPtr = eWithFuncPtr.WithTime(time.Now()) 250 251 assert.Equal(eWithFunc.err, `can not add field "func"`) 252 assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) 253} 254 255func TestEntryLogfLevel(t *testing.T) { 256 logger := New() 257 buffer := &bytes.Buffer{} 258 logger.Out = buffer 259 logger.SetLevel(InfoLevel) 260 entry := NewEntry(logger) 261 262 entry.Logf(DebugLevel, "%s", "debug") 263 assert.NotContains(t, buffer.String(), "debug") 264 265 entry.Logf(WarnLevel, "%s", "warn") 266 assert.Contains(t, buffer.String(), "warn") 267} 268 269func TestEntryReportCallerRace(t *testing.T) { 270 logger := New() 271 entry := NewEntry(logger) 272 go func() { 273 logger.SetReportCaller(true) 274 }() 275 go func() { 276 entry.Info("should not race") 277 }() 278} 279