Created
February 8, 2020 20:20
-
-
Save cmoad/90dedff4917a9cca96d151ff1df497f8 to your computer and use it in GitHub Desktop.
BugSnag stacktrace support for github.com/pkg/errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package service | |
import ( | |
"github.com/bugsnag/bugsnag-go" | |
bugsnag_errors "github.com/bugsnag/bugsnag-go/errors" | |
"github.com/pkg/errors" | |
log "github.com/sirupsen/logrus" | |
) | |
// stable interface declared by github.com/pkg/errors | |
// https://github.com/pkg/errors/blob/master/errors.go | |
type stackTracer interface { | |
StackTrace() errors.StackTrace | |
} | |
// stable interface declared by github.com/pkg/errors | |
// https://github.com/pkg/errors/blob/master/errors.go | |
type causer interface { | |
Cause() error | |
} | |
// implements ErrorWithCallers interface declared by bugsnag | |
type errorWithCallers struct { | |
error | |
} | |
// Callers returns the raw stack from a github.com/pkg/errors error | |
func (err *errorWithCallers) Callers() (callers []uintptr) { | |
// find the innermost error that implements stackTracer | |
innerMostErrorWithStack := err.error.(stackTracer) | |
for { | |
// try to get an underlying error | |
causer, ok := innerMostErrorWithStack.(causer) | |
if !ok { | |
break | |
} | |
// check if the cause implements stackTracer | |
cause, ok := causer.Cause().(stackTracer) | |
if !ok { | |
break | |
} | |
// replace the error with the cause | |
innerMostErrorWithStack = cause | |
} | |
stacktrace := innerMostErrorWithStack.StackTrace() | |
callers = make([]uintptr, len(stacktrace)) | |
for i, pc := range stacktrace { | |
callers[i] = uintptr(pc) | |
} | |
return | |
} | |
// ReportError logs the given error to bugsnag and injects the stacktrace | |
// the function signature exactly matches bugsnag.Notify | |
func ReportError(err error, rawData ...interface{}) { | |
// if the error contains a stacktrack from github.com/pkg/errors, use it | |
if _, ok := error(err).(stackTracer); ok { | |
if err := bugsnag.Notify(&errorWithCallers{err}, rawData...); err != nil { | |
log.WithError(err).Error("failed to report error to bugsnag") | |
} | |
} else { | |
if err := bugsnag.Notify(bugsnag_errors.New(err, 1), rawData...); err != nil { | |
log.WithError(err).Error("failed to report error to bugsnag") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment