forked from newrelic/go-agent
/
nrpkgerrors.go
84 lines (72 loc) · 1.82 KB
/
nrpkgerrors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
// Package nrpkgerrors introduces support for https://github.com/pkg/errors.
//
// This package improves the class and stack-trace fields of pkg/error errors
// when they are recorded with Transaction.NoticeError.
//
package nrpkgerrors
import (
"fmt"
newrelic "github.com/newrelic/go-agent"
"github.com/newrelic/go-agent/internal"
"github.com/pkg/errors"
)
func init() { internal.TrackUsage("integration", "pkg-errors") }
type nrpkgerror struct {
error
}
// stackTracer is an error that also knows about its StackTrace.
// All wrapped errors from github.com/pkg/errors implement this interface.
type stackTracer interface {
StackTrace() errors.StackTrace
}
func deepestStackTrace(err error) errors.StackTrace {
var last stackTracer
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 nil
}
return last.StackTrace()
}
func transformStackTrace(orig errors.StackTrace) []uintptr {
st := make([]uintptr, len(orig))
for i, frame := range orig {
st[i] = uintptr(frame)
}
return st
}
func (e nrpkgerror) StackTrace() []uintptr {
st := deepestStackTrace(e.error)
if nil == st {
return nil
}
return transformStackTrace(st)
}
func (e nrpkgerror) ErrorClass() string {
if ec, ok := e.error.(newrelic.ErrorClasser); ok {
return ec.ErrorClass()
}
cause := errors.Cause(e.error)
if ec, ok := cause.(newrelic.ErrorClasser); ok {
return ec.ErrorClass()
}
return fmt.Sprintf("%T", cause)
}
// Wrap wraps a pkg/errors error so that when noticed by
// newrelic.Transaction.NoticeError it gives an improved stacktrace and class
// type.
func Wrap(e error) error {
return nrpkgerror{e}
}