Update sentry client

This commit is contained in:
Pavel Škoda
2020-11-16 19:11:12 +01:00
committed by Jakub Cuth
parent 874882b554
commit 7b44f12ab1
5 changed files with 30 additions and 209 deletions

View File

@ -18,135 +18,15 @@
package sentry
import (
"fmt"
"regexp"
"errors"
"runtime"
"runtime/pprof"
"strconv"
"strings"
"time"
"github.com/getsentry/raven-go"
"github.com/getsentry/sentry-go"
log "github.com/sirupsen/logrus"
)
const fileParseError = "[file parse error]"
var isGoroutine = regexp.MustCompile("^goroutine [[:digit:]]+.*") //nolint[gochecknoglobals]
// Threads implements standard sentry thread report.
type Threads struct {
Values []Thread `json:"values"`
}
// Class specifier.
func (s *Threads) Class() string { return "threads" }
// Thread wraps a single stacktrace.
type Thread struct {
ID int `json:"id"`
Name string `json:"name"`
Crashed bool `json:"crashed"`
Stacktrace *raven.Stacktrace `json:"stacktrace"`
}
// TraceAllRoutines traces all goroutines and saves them to the current object.
func (s *Threads) TraceAllRoutines() {
s.Values = []Thread{}
goroutines := &strings.Builder{}
_ = pprof.Lookup("goroutine").WriteTo(goroutines, 2)
thread := Thread{ID: -1}
var frame *raven.StacktraceFrame
for _, v := range strings.Split(goroutines.String(), "\n") {
// Ignore empty lines.
if v == "" {
continue
}
// New routine.
if isGoroutine.MatchString(v) {
if thread.ID >= 0 {
s.Values = append(s.Values, thread)
}
thread = Thread{ID: thread.ID + 1, Name: v, Crashed: thread.ID == -1, Stacktrace: &raven.Stacktrace{Frames: []*raven.StacktraceFrame{}}}
continue
}
// New function.
if frame == nil {
frame = &raven.StacktraceFrame{Function: v}
continue
}
// Set filename and add frame.
if frame.Filename == "" {
fld := strings.Fields(v)
if len(fld) != 2 {
frame.Filename = fileParseError
frame.AbsolutePath = v
} else {
frame.Filename = fld[0]
sp := strings.Split(fld[0], ":")
if len(sp) > 1 {
i, err := strconv.Atoi(sp[len(sp)-1])
if err == nil {
frame.Filename = strings.Join(sp[:len(sp)-1], ":")
frame.Lineno = i
}
}
}
if frame.AbsolutePath == "" && frame.Filename != fileParseError {
frame.AbsolutePath = frame.Filename
if sp := strings.Split(frame.Filename, "/"); len(sp) > 1 {
frame.Filename = sp[len(sp)-1]
}
}
thread.Stacktrace.Frames = append([]*raven.StacktraceFrame{frame}, thread.Stacktrace.Frames...)
frame = nil
continue
}
}
// Add last thread.
s.Values = append(s.Values, thread)
}
func findPanicSender(s *Threads, err error) string {
out := "error nil"
if err != nil {
out = err.Error()
}
for _, thread := range s.Values {
if !thread.Crashed {
continue
}
for i, fr := range thread.Stacktrace.Frames {
if strings.HasSuffix(fr.Filename, "panic.go") && strings.HasPrefix(fr.Function, "panic") {
// Next frame if any.
j := 0
if i > j {
j = i - 1
}
// Directory and filename.
fname := thread.Stacktrace.Frames[j].AbsolutePath
if sp := strings.Split(fname, "/"); len(sp) > 2 {
fname = strings.Join(sp[len(sp)-2:], "/")
}
// Line number.
if ln := thread.Stacktrace.Frames[j].Lineno; ln > 0 {
fname = fmt.Sprintf("%s:%d", fname, ln)
}
out = fmt.Sprintf("%s: %s", fname, out)
break // Just first panic.
}
}
}
return out
}
// ReportSentryCrash reports a sentry crash with stacktrace from all goroutines.
// ReportSentryCrash reports a sentry crash.
func ReportSentryCrash(clientID, appVersion, userAgent string, reportErr error) (err error) {
if reportErr == nil {
return
@ -160,18 +40,16 @@ func ReportSentryCrash(clientID, appVersion, userAgent string, reportErr error)
"UserID": "",
}
threads := &Threads{}
threads.TraceAllRoutines()
errorWithFile := findPanicSender(threads, reportErr)
packet := raven.NewPacket(errorWithFile, threads)
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetTags(tags)
sentry.CaptureException(reportErr)
})
eventID, ch := raven.Capture(packet, tags)
if err = <-ch; err == nil {
log.WithField("errorID", eventID).Warn("Reported sentry error")
} else {
log.WithField("error", reportErr).WithError(err).Error("Failed to report sentry error")
if !sentry.Flush(time.Second * 10) {
log.WithField("error", reportErr).Error("failed to report sentry error")
return errors.New("failed to report sentry error")
}
return err
log.WithField("error", reportErr).Warn("reported sentry error")
return
}