977e03308a
When calling Entry.log a panic inside some of the locking blocks could cause the whole logger to deadlock. One of the ways this could happen is for a hook to cause a panic, when this happens the lock is never unlocked and the library deadlocks, causing the code that is calling it to deadlock as well. This changes how locking happens with unlocks at defer blocks so even if a panic happens somewhere along the log call the library will still unlock and continue to function.
116 lines
2.1 KiB
Go
116 lines
2.1 KiB
Go
package logrus
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestEntryWithError(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
defer func() {
|
|
ErrorKey = "error"
|
|
}()
|
|
|
|
err := fmt.Errorf("kaboom at layer %d", 4711)
|
|
|
|
assert.Equal(err, WithError(err).Data["error"])
|
|
|
|
logger := New()
|
|
logger.Out = &bytes.Buffer{}
|
|
entry := NewEntry(logger)
|
|
|
|
assert.Equal(err, entry.WithError(err).Data["error"])
|
|
|
|
ErrorKey = "err"
|
|
|
|
assert.Equal(err, entry.WithError(err).Data["err"])
|
|
|
|
}
|
|
|
|
func TestEntryPanicln(t *testing.T) {
|
|
errBoom := fmt.Errorf("boom time")
|
|
|
|
defer func() {
|
|
p := recover()
|
|
assert.NotNil(t, p)
|
|
|
|
switch pVal := p.(type) {
|
|
case *Entry:
|
|
assert.Equal(t, "kaboom", pVal.Message)
|
|
assert.Equal(t, errBoom, pVal.Data["err"])
|
|
default:
|
|
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
|
}
|
|
}()
|
|
|
|
logger := New()
|
|
logger.Out = &bytes.Buffer{}
|
|
entry := NewEntry(logger)
|
|
entry.WithField("err", errBoom).Panicln("kaboom")
|
|
}
|
|
|
|
func TestEntryPanicf(t *testing.T) {
|
|
errBoom := fmt.Errorf("boom again")
|
|
|
|
defer func() {
|
|
p := recover()
|
|
assert.NotNil(t, p)
|
|
|
|
switch pVal := p.(type) {
|
|
case *Entry:
|
|
assert.Equal(t, "kaboom true", pVal.Message)
|
|
assert.Equal(t, errBoom, pVal.Data["err"])
|
|
default:
|
|
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
|
}
|
|
}()
|
|
|
|
logger := New()
|
|
logger.Out = &bytes.Buffer{}
|
|
entry := NewEntry(logger)
|
|
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
|
}
|
|
|
|
const (
|
|
badMessage = "this is going to panic"
|
|
panicMessage = "this is broken"
|
|
)
|
|
|
|
type panickyHook struct{}
|
|
|
|
func (p *panickyHook) Levels() []Level {
|
|
return []Level{InfoLevel}
|
|
}
|
|
|
|
func (p *panickyHook) Fire(entry *Entry) error {
|
|
if entry.Message == badMessage {
|
|
panic(panicMessage)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func TestEntryHooksPanic(t *testing.T) {
|
|
logger := New()
|
|
logger.Out = &bytes.Buffer{}
|
|
logger.Level = InfoLevel
|
|
logger.Hooks.Add(&panickyHook{})
|
|
|
|
defer func() {
|
|
p := recover()
|
|
assert.NotNil(t, p)
|
|
assert.Equal(t, panicMessage, p)
|
|
|
|
entry := NewEntry(logger)
|
|
entry.Info("another message")
|
|
}()
|
|
|
|
entry := NewEntry(logger)
|
|
entry.Info(badMessage)
|
|
}
|