Skip to content

Instantly share code, notes, and snippets.

@cmoad
Created February 8, 2020 20:20
Show Gist options
  • Save cmoad/90dedff4917a9cca96d151ff1df497f8 to your computer and use it in GitHub Desktop.
Save cmoad/90dedff4917a9cca96d151ff1df497f8 to your computer and use it in GitHub Desktop.
BugSnag stacktrace support for github.com/pkg/errors
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