From e2798ae20423a9321141051020af04bd6f7524a9 Mon Sep 17 00:00:00 2001 From: hiroshi Date: Fri, 19 May 2017 10:02:59 +0900 Subject: [PATCH 1/2] Experimental support for stacktrace of github.com/pkg/errors. --- client.go | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 07ed9c5..dd3fb29 100644 --- a/client.go +++ b/client.go @@ -9,7 +9,6 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -24,6 +23,7 @@ import ( "time" "github.com/certifi/gocertifi" + "github.com/pkg/errors" ) const ( @@ -617,7 +617,33 @@ 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)))...) + var stacktrace *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, 3, client.IncludePaths()) + if frame != nil { + frames = append([]*StacktraceFrame{frame}, frames...) + } + } + stacktrace = &Stacktrace{Frames: frames} + } else { + stacktrace = NewStacktrace(1, 3, client.includePaths) + } + + packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, stacktrace))...) eventID, _ := client.Capture(packet, tags) return eventID From c06778cb55142be086e41d25c79de4e4d7f4f6c3 Mon Sep 17 00:00:00 2001 From: hiroshi Date: Mon, 29 May 2017 21:40:17 +0900 Subject: [PATCH 2/2] implement GetOrNewStacktrace(). --- client.go | 30 ++---------------------------- http.go | 2 +- stacktrace.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/client.go b/client.go index dd3fb29..bdc59b5 100644 --- a/client.go +++ b/client.go @@ -9,6 +9,7 @@ import ( "encoding/base64" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -23,7 +24,6 @@ import ( "time" "github.com/certifi/gocertifi" - "github.com/pkg/errors" ) const ( @@ -617,33 +617,7 @@ func (client *Client) CaptureError(err error, tags map[string]string, interfaces return "" } - var stacktrace *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, 3, client.IncludePaths()) - if frame != nil { - frames = append([]*StacktraceFrame{frame}, frames...) - } - } - stacktrace = &Stacktrace{Frames: frames} - } else { - stacktrace = NewStacktrace(1, 3, client.includePaths) - } - - packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, stacktrace))...) + 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.