Skip to content

Instantly share code, notes, and snippets.

@Azuka
Created September 6, 2019 02:17
Show Gist options
  • Save Azuka/07bb3797696a6c413419b2b65d58db6e to your computer and use it in GitHub Desktop.
Save Azuka/07bb3797696a6c413419b2b65d58db6e to your computer and use it in GitHub Desktop.
Elastic APM Go Deep Stacktrace
package tracer
import (
"context"
"github.com/pkg/errors"
"go.elastic.co/apm"
"runtime"
)
// Lifted from github.com/pkg/errors
func callers() errors.StackTrace {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st []uintptr = pcs[0:n]
f := make([]errors.Frame, len(st))
for i := 0; i < len(f); i++ {
f[i] = errors.Frame((st)[i])
}
return f
}
type unwrappedError struct {
error
}
type stackTracer interface {
StackTrace() errors.StackTrace
}
func Unwrap(e error) error {
return &unwrappedError{error: e}
}
func (u *unwrappedError) Cause() error {
return u.error
}
func (u *unwrappedError) StackTrace() errors.StackTrace {
st := callers()
var last stackTracer
err := u.error
// See https://github.com/newrelic/go-agent/blob/c680931e5ab45efd53e933df0350ff469d8c3d24/_integrations/nrpkgerrors/nrpkgerrors.go#L28
for err != nil {
if err, ok := err.(stackTracer); ok {
last = err
}
cause, ok := err.(interface {
Cause() error
})
if !ok {
break
}
err = cause.Cause()
}
if last == nil {
return st
}
return last.StackTrace()
}
// CaptureError reports an error to APM with the deepest Stacktrace. See https://github.com/elastic/apm-agent-go/issues/423
// Use this instead of apm.CaptureError
func CaptureError(ctx context.Context, err error) *apm.Error {
return apm.CaptureError(ctx, Unwrap(err))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment