Skip to content

Commit

Permalink
do a better job of printing the panic stack trace
Browse files Browse the repository at this point in the history
  • Loading branch information
Greg Weber committed Mar 7, 2024
1 parent cbf445e commit d401288
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 14 deletions.
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
module github.com/gregwebs/go-recovery

go 1.18
go 1.21

toolchain go1.21.5

require (
github.com/gregwebs/errors v1.1.0
github.com/gregwebs/errors v1.2.2
github.com/stretchr/testify v1.8.1
)

Expand Down
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gregwebs/errors v1.0.0 h1:Ov7HzBs79i7TcqQnfxyxLT8gttpTzGT3cDq70J8zkpE=
github.com/gregwebs/errors v1.0.0/go.mod h1:hUKQdGWTRTHMeAXJudXmN/BMLe+L51MG+OnRz72ZeBc=
github.com/gregwebs/errors v1.1.0 h1:I0CqB+CPseFcYyoR3t/+mOVPgdukwTUcZKAN8nm7xRY=
github.com/gregwebs/errors v1.1.0/go.mod h1:oGma9emsMfJUvDNUK5O72GU4o6WBKiQWK7dl1md9Plo=
github.com/gregwebs/errors v1.20.0 h1:rOMGCP1UplGbTBXSYFt458QSlFZiT2WB/dK7yLgE5Es=
github.com/gregwebs/errors v1.20.0/go.mod h1:oGma9emsMfJUvDNUK5O72GU4o6WBKiQWK7dl1md9Plo=
github.com/gregwebs/errors v1.2.2 h1:JQG47s42qKzMPdIT8pmCkZ+2Trhoyskgimxbyp7lD+U=
github.com/gregwebs/errors v1.2.2/go.mod h1:1NkCObP7+scylHlC69lwHl2ACOHwktWYrZV4EJDEl6g=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
33 changes: 31 additions & 2 deletions recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package recovery

import (
"fmt"
"io"
"log"

"github.com/gregwebs/errors"
Expand All @@ -25,9 +26,35 @@ func (p PanicError) Unwrap() error {

func (p PanicError) Error() string {
if err := p.Unwrap(); err != nil {
return err.Error()
return "panic: " + err.Error()
} else {
return fmt.Sprintf("%v", p.Panic)
return "panic: " + fmt.Sprintf("%v", p.Panic)
}
}

// This works with the extended syntax "%+v" for printing stack traces
func (p PanicError) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
if _, errWrite := fmt.Fprint(s, "panic: "); errWrite != nil {
errors.HandleWriteError(errWrite)
}
p := p.Panic
if f, ok := p.(fmt.Formatter); ok {
f.Format(s, verb)
} else {
if _, errWrite := fmt.Fprintf(s, "%+v\n", p); errWrite != nil {
errors.HandleWriteError(errWrite)
}
}
return
}
fallthrough
case 's', 'q':
if _, errWrite := io.WriteString(s, p.Error()); errWrite != nil {
errors.HandleWriteError(errWrite)
}
}
}

Expand Down Expand Up @@ -156,6 +183,8 @@ func ToError(r interface{}) error {
return r.Unwrap()

// return a PanicError as is
case PanicError:
return r
case *PanicError:
if r == nil {
return nil
Expand Down
59 changes: 55 additions & 4 deletions recovery_test.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,79 @@
package recovery_test

import (
"errors"
"fmt"
"testing"

"github.com/gregwebs/errors"
"github.com/gregwebs/go-recovery"
"github.com/stretchr/testify/assert"
)

func TestCall(t *testing.T) {
func TestCallNil(t *testing.T) {
// return nil- no error
err := recovery.Call(func() error {
return nil
})
assert.Nil(t, err)
err = recovery.Call(func() error {
assert.False(t, errors.HasStack(err))
}

func TestCallError(t *testing.T) {
// return a basic error
err := recovery.Call(func() error {
return fmt.Errorf("return error")
})
assert.NotNil(t, err)
assert.False(t, errors.HasStack(err))

// return an error with stack trace
err = recovery.Call(func() error {
return errors.Errorf("return error with stack")
})
assert.NotNil(t, err)
assert.True(t, errors.HasStack(err))
}

func TestCallPanicValue(t *testing.T) {
// panic string
err := recovery.Call(func() error {
panic("panic")
})
assert.NotNil(t, err)
assert.Equal(t, "panic", err.Error())
assert.True(t, errors.HasStack(err))
assert.Equal(t, "panic: panic", err.Error())

// panic nil
err = recovery.Call(func() error {
panic(nil)
})
assert.NotNil(t, err)
assert.True(t, errors.HasStack(err))
assert.Equal(t, "panic: panic called with nil argument", err.Error())
}

var standardErr = fmt.Errorf("error standard")

func TestCallPanicError(t *testing.T) {
// panic standard error
err := recovery.Call(func() error {
panic(standardErr)
})
assert.NotNil(t, err)
assert.IsType(t, errors.AddStack(standardErr), err)
assert.True(t, errors.HasStack(err))
assert.Equal(t, "panic: error standard", err.Error())

// panic error
err = recovery.Call(func() error {
panic(errors.New("error with stack"))
})
assert.IsType(t, recovery.PanicError{}, err)
assert.NotNil(t, err)
assert.True(t, errors.HasStack(err))
assert.Equal(t, "panic: error with stack", err.Error())
fullPrint := fmt.Sprintf("%+v", err)
assert.Contains(t, fullPrint, "recovery_test.go")
}

func TestCallThrown(t *testing.T) {
Expand Down

0 comments on commit d401288

Please sign in to comment.