Skip to content

Commit

Permalink
provide more exensibility around fingerprinting (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
gregwebs authored Sep 24, 2024
1 parent 3e8d29c commit 6c1c28a
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 23 deletions.
9 changes: 7 additions & 2 deletions gin/gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ import (
type Sentry500Options struct {
ExtractContext func(*gin.Context, *sentry.Scope)
NoLogResponseBody bool
FingerprintOpts mdlwrsentry.FingerprintOpts
}

var DefaultSentry500Opts = Sentry500Options{
FingerprintOpts: mdlwrsentry.DefaultFingerprinter,
}

func MiddlewareSentry500(ctx *gin.Context) {
MiddlewareSentry500Opts(Sentry500Options{})(ctx)
MiddlewareSentry500Opts(DefaultSentry500Opts)(ctx)
}

func MiddlewareSentry500Opts(opts Sentry500Options) func(*gin.Context) {
Expand All @@ -27,7 +32,7 @@ func MiddlewareSentry500Opts(opts Sentry500Options) func(*gin.Context) {
if hubOrig == nil {
hubOrig = sentry.CurrentHub().Clone()
}
hub := mdlwrsentry.HubCustomFingerprint(hubOrig, mdlwrsentry.DefaultFingerprintErrorHandler)
hub := mdlwrsentry.HubCustomFingerprint(hubOrig, opts.FingerprintOpts)
hub.Scope().SetRequest(ctx.Request)
urlStr := ""
if url := ctx.Request.URL; url != nil {
Expand Down
7 changes: 6 additions & 1 deletion goa/goa.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (
type Sentry500Options struct {
ExtractContext func(context.Context, *sentry.Scope)
NoLogResponseBody bool
FingerprintOpts mdlwrsentry.FingerprintOpts
}

var DefaultSentry500Opts = Sentry500Options{
FingerprintOpts: mdlwrsentry.DefaultFingerprinter,
}

// MiddlewareSentry500 is a Goa middleware that captures the response status code and sends to Sentry if code=500.
Expand All @@ -31,7 +36,7 @@ func MiddlewareSentry500(opts Sentry500Options) func(http.Handler) http.Handler
if hubOrig == nil {
hubOrig = sentry.CurrentHub().Clone()
}
hub := mdlwrsentry.HubCustomFingerprint(hubOrig, mdlwrsentry.DefaultFingerprintErrorHandler)
hub := mdlwrsentry.HubCustomFingerprint(hubOrig, opts.FingerprintOpts)
hub.Scope().SetRequest(r)
urlStr := ""
if url := r.URL; url != nil {
Expand Down
60 changes: 40 additions & 20 deletions sentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,49 @@ func (e500 SentryError500) Error() string {
return "500 " + e500.Url + ":" + e500.Body
}

func (e500 SentryError500) Fingerprint(_ []string) ([]string, error) {
message := e500.Body
if len(e500.Body) > 15 {
message = e500.Body[0:15]
}
u, err := url.Parse(e500.Url)
if err != nil {
return nil, err
}
newPath := NormalizeUrlPathForSentry(u, "")
return []string{newPath, message}, nil
}

// group on the url and the beginning of the body.
// The same url can have different errors: thus looking at the response body.
// the longer the body is, the more likely it is to contain variable
// So for now try looking at a beginning snippet of the body.
// The URL is normalized so that any path part with a number is replaced by a placeholder value
func SentryFingerprint(event *sentry.Event, hint *sentry.EventHint) error {
if oe := hint.OriginalException; oe != nil {
//nolint:errorlint
if ex, ok := oe.(SentryError500); ok {
message := ex.Body
if len(ex.Body) > 15 {
message = ex.Body[0:15]
}
u, err := url.Parse(ex.Url)
if err != nil {
return err
}
newPath := NormalizeUrlPathForSentry(u, "")
event.Fingerprint = []string{newPath, message}
}
func Fingerprint500(err error, fingerprint []string) ([]string, error) {
//nolint:errorlint
if ex, ok := err.(SentryError500); !ok {
return ex.Fingerprint(fingerprint)
}
return nil
return nil, nil
}

func DefaultFingerprintErrorHandler(err error) {
slog.Error("error during fingerprinting", "error", err)
}

func HubCustomFingerprint(hub *sentry.Hub, fingerprintErrHandler func(err error)) *sentry.Hub {
type Fingerprint func(err error, fingerprint []string) ([]string, error)

type FingerprintOpts struct {
ErrHandler func(err error)
Fingerprinters []Fingerprint
}

var DefaultFingerprinter = FingerprintOpts{
ErrHandler: DefaultFingerprintErrorHandler,
Fingerprinters: []Fingerprint{Fingerprint500},
}

func HubCustomFingerprint(hub *sentry.Hub, fingerprintOpts FingerprintOpts) *sentry.Hub {
clientOld, scope := hub.Client(), hub.Scope()
options := sentry.ClientOptions{}
if clientOld != nil {
Expand All @@ -64,9 +78,15 @@ func HubCustomFingerprint(hub *sentry.Hub, fingerprintErrHandler func(err error)
options.AttachStacktrace = false
// See: https://docs.sentry.io/platforms/go/usage/sdk-fingerprinting/
options.BeforeSend = func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
err := SentryFingerprint(event, hint)
if err != nil {
fingerprintErrHandler(err)
if oe := hint.OriginalException; oe != nil {
for _, fingerprinter := range fingerprintOpts.Fingerprinters {
fingerprint, err := fingerprinter(oe, event.Fingerprint)
if err != nil {
fingerprintOpts.ErrHandler(err)
} else if fingerprint != nil {
event.Fingerprint = fingerprint
}
}
}
return event
}
Expand Down

0 comments on commit 6c1c28a

Please sign in to comment.