diff --git a/client.go b/client.go index 9d43641..f178210 100644 --- a/client.go +++ b/client.go @@ -639,7 +639,7 @@ func (client *Client) CaptureError(err error, tags map[string]string, interfaces return "" } - packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, NewStacktrace(1, 3, client.includePaths)))...) + packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, GetOrNewStacktrace(err, 1, 3, client.includePaths)))...) eventID, _ := client.Capture(packet, tags) return eventID diff --git a/http.go b/http.go index 32107b8..1a2e881 100644 --- a/http.go +++ b/http.go @@ -73,7 +73,7 @@ func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http if rval := recover(); rval != nil { debug.PrintStack() rvalStr := fmt.Sprint(rval) - packet := NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r)) + packet := NewPacket(rvalStr, NewException(errors.New(rvalStr), GetOrNewStacktrace(rval.(error), 2, 3, nil)), NewHttp(r)) Capture(packet, nil) w.WriteHeader(http.StatusInternalServerError) } diff --git a/stacktrace.go b/stacktrace.go index 114c5f9..12ae884 100644 --- a/stacktrace.go +++ b/stacktrace.go @@ -13,6 +13,8 @@ import ( "runtime" "strings" "sync" + + "github.com/pkg/errors" ) // https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces @@ -49,6 +51,35 @@ type StacktraceFrame struct { InApp bool `json:"in_app"` } +// Try to get stacktrace from err as an interface of github.com/pkg/errors, or else NewStacktrace() +func GetOrNewStacktrace(err error, skip int, context int, appPackagePrefixes []string) *Stacktrace { + stacktracer, errHasStacktrace := err.(interface { + StackTrace() errors.StackTrace + }) + if errHasStacktrace { + var frames []*StacktraceFrame + for _, f := range stacktracer.StackTrace() { + pc := uintptr(f) - 1 + fn := runtime.FuncForPC(pc) + var file string + var line int + if fn != nil { + file, line = fn.FileLine(pc) + } else { + file = "unknown" + } + frame := NewStacktraceFrame(pc, file, line, context, appPackagePrefixes) + if frame != nil { + frames = append([]*StacktraceFrame{frame}, frames...) + } + } + return &Stacktrace{Frames: frames} + } else { + return NewStacktrace(skip + 1, context, appPackagePrefixes) + } +} + + // Intialize and populate a new stacktrace, skipping skip frames. // // context is the number of surrounding lines that should be included for context.