-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
94 lines (76 loc) · 1.96 KB
/
errors.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
85
86
87
88
89
90
91
92
93
94
package logz
import (
"context"
"fmt"
"reflect"
"runtime"
"github.com/getsentry/sentry-go"
"github.com/ibrt/golang-errors/errorz"
"github.com/ibrt/golang-inject-clock/clockz"
)
const (
maxErrorDepth = 10
statusKey = "status"
unwrappedKey = "unwrapped[%v][%v]"
)
func errorToSentryEvent(ctx context.Context, err error, level Level) *sentry.Event {
err = errorz.Wrap(err, errorz.SkipPackage()) // ensure error is wrapped to start
event := sentry.NewEvent()
event.Timestamp = clockz.Get(ctx).Now()
event.Level = level.toSentry()
if status := errorz.GetStatus(err); status != 0 {
event.Extra[statusKey] = status.Int()
}
for k, v := range errorz.GetMetadata(err) {
event.Extra[k] = v
}
for i := 0; i < maxErrorDepth && err != nil; i++ {
uErr := errorz.Unwrap(err)
uType := reflect.TypeOf(uErr).String()
event.Exception = append(event.Exception, sentry.Exception{
Type: func() string {
if id := errorz.GetID(err); id != "" {
return id.String()
}
return uType
}(),
Value: err.Error(),
Stacktrace: extractSentryStacktrace(err),
})
err = uErr
switch uType {
case "*errors.errorString":
default:
event.Extra[fmt.Sprintf(unwrappedKey, i, reflect.TypeOf(err).String())] = err
}
switch pErr := err.(type) {
case interface{ Unwrap() error }:
err = pErr.Unwrap()
case interface{ Cause() error }:
err = pErr.Cause()
default:
err = nil
}
}
return event
}
func extractSentryStacktrace(err error) *sentry.Stacktrace {
if errorz.Unwrap(err) == err {
return sentry.ExtractStacktrace(err)
}
return callersToSentryStacktrace(errorz.GetCallers(err))
}
func callersToSentryStacktrace(callers []uintptr) *sentry.Stacktrace {
s := &sentry.Stacktrace{
Frames: make([]sentry.Frame, 0),
}
callersFrames := runtime.CallersFrames(callers)
for {
callerFrame, more := callersFrames.Next()
s.Frames = append([]sentry.Frame{sentry.NewFrame(callerFrame)}, s.Frames...)
if !more {
break
}
}
return s
}