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

@ -1,6 +1,10 @@
# ProtonMail Bridge and Import-Export app Changelog # ProtonMail Bridge and Import-Export app Changelog
Changelog [format](http://keepachangelog.com/en/1.0.0/) Changelog [format](http://keepachangelog.com/en/1.0.0/)
## Untaged
### Changed
* GODT-180 Updated Sentry client.
## [IE 1.2.1] Elbe ## [IE 1.2.1] Elbe

View File

@ -22,7 +22,7 @@ import (
"runtime" "runtime"
"github.com/ProtonMail/proton-bridge/pkg/constants" "github.com/ProtonMail/proton-bridge/pkg/constants"
"github.com/getsentry/raven-go" "github.com/getsentry/sentry-go"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -51,10 +51,14 @@ var (
// Main sets up Sentry, filters out unwanted args, creates app and runs it. // Main sets up Sentry, filters out unwanted args, creates app and runs it.
func Main(appName, usage string, extraFlags []cli.Flag, run func(*cli.Context) error) { func Main(appName, usage string, extraFlags []cli.Flag, run func(*cli.Context) error) {
if err := raven.SetDSN(constants.DSNSentry); err != nil { err := sentry.Init(sentry.ClientOptions{
Dsn: constants.DSNSentry,
Release: constants.Revision,
})
if err != nil {
log.WithError(err).Errorln("Can not setup sentry DSN") log.WithError(err).Errorln("Can not setup sentry DSN")
} }
raven.SetRelease(constants.Revision)
filterProcessSerialNumberFromArgs() filterProcessSerialNumberFromArgs()
filterRestartNumberFromArgs() filterRestartNumberFromArgs()

View File

@ -18,7 +18,7 @@
package pmapi package pmapi
import ( import (
"github.com/getsentry/raven-go" "github.com/getsentry/sentry-go"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -119,7 +119,11 @@ func (c *client) UpdateUser() (user *User, err error) {
} }
c.user = user c.user = user
raven.SetUserContext(&raven.User{ID: user.ID}) sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetUser(sentry.User{
ID: user.ID,
})
})
var tmpList AddressList var tmpList AddressList
if tmpList, err = c.GetAddresses(); err == nil { if tmpList, err = c.GetAddresses(); err == nil {

View File

@ -18,135 +18,15 @@
package sentry package sentry
import ( import (
"fmt" "errors"
"regexp"
"runtime" "runtime"
"runtime/pprof" "time"
"strconv"
"strings"
"github.com/getsentry/raven-go" "github.com/getsentry/sentry-go"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
const fileParseError = "[file parse error]" // ReportSentryCrash reports a sentry crash.
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.
func ReportSentryCrash(clientID, appVersion, userAgent string, reportErr error) (err error) { func ReportSentryCrash(clientID, appVersion, userAgent string, reportErr error) (err error) {
if reportErr == nil { if reportErr == nil {
return return
@ -160,18 +40,16 @@ func ReportSentryCrash(clientID, appVersion, userAgent string, reportErr error)
"UserID": "", "UserID": "",
} }
threads := &Threads{} sentry.WithScope(func(scope *sentry.Scope) {
threads.TraceAllRoutines() scope.SetTags(tags)
errorWithFile := findPanicSender(threads, reportErr) sentry.CaptureException(reportErr)
packet := raven.NewPacket(errorWithFile, threads) })
eventID, ch := raven.Capture(packet, tags) if !sentry.Flush(time.Second * 10) {
log.WithField("error", reportErr).Error("failed to report sentry error")
if err = <-ch; err == nil { return errors.New("failed to report sentry error")
log.WithField("errorID", eventID).Warn("Reported sentry error")
} else {
log.WithField("error", reportErr).WithError(err).Error("Failed to report sentry error")
} }
return err log.WithField("error", reportErr).Warn("reported sentry error")
return
} }

View File

@ -1,69 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package sentry
import (
"errors"
"testing"
"github.com/getsentry/raven-go"
)
func TestSentryCrashReport(t *testing.T) {
if err := ReportSentryCrash(
"clientID",
"appVersion",
"useragent",
errors.New("Testing crash report - api proxy; goroutines with threads, find origin"),
); err != nil {
t.Fatal("Expected no error while report, but have", err)
}
}
func (s *Threads) TraceAllRoutinesTest() {
s.Values = []Thread{
{
ID: 0,
Name: "goroutine 20 [running]",
Crashed: true,
Stacktrace: &raven.Stacktrace{
Frames: []*raven.StacktraceFrame{
{
Filename: "/home/dev/build/go-1.10.2/go/src/runtime/pprof/pprof.go",
Function: "runtime/pprof.writeGoroutineStacks(0x9b7de0, 0xc4203e2900, 0xd0, 0xd0)",
Lineno: 650,
},
},
},
},
{
ID: 1,
Name: "goroutine 20 [chan receive]",
Crashed: false,
Stacktrace: &raven.Stacktrace{
Frames: []*raven.StacktraceFrame{
{
Filename: "/home/dev/build/go-1.10.2/go/src/testing/testing.go",
Function: "testing.(*T).Run(0xc4203e42d0, 0x90f445, 0x15, 0x97d358, 0x47a501)",
Lineno: 825,
},
},
},
},
}
}