-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherrors.go
174 lines (145 loc) · 3.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package toolbox
import (
"fmt"
"regexp"
"strings"
"github.com/pkg/errors"
)
type causer interface {
Cause() error
}
type causerBehavior struct {
cause error
}
func (e *causerBehavior) Cause() error { return e.cause }
func findBehavior(err error, found func(err error) bool) error {
for err != nil {
if !found(err) {
if cause, ok := err.(causer); ok {
err = cause.Cause()
continue
} else {
break
}
}
return err
}
return nil
}
type stackTracer interface {
StackTrace() errors.StackTrace
}
var stackFileRegex = regexp.MustCompile(`([^\(\)]+)\..+`)
// HasStack returns where the error was thrown if possible.
func HasStack(err error) (location string, ok bool) {
if foundErr := findBehavior(err, func(err error) bool { _, ok := err.(stackTracer); return ok }); foundErr != nil {
stackTrace := foundErr.(stackTracer).StackTrace()
if len(stackTrace) > 0 {
if stack := strings.SplitN(fmt.Sprintf("%+v", stackTrace[0]), "\n\t", 2); len(stack) == 2 {
if matches := stackFileRegex.FindStringSubmatch(stack[0]); len(matches) == 2 {
location = fmt.Sprintf("%s/%v", matches[1], stackTrace[0])
}
}
return location, true
}
}
return location, false
}
type keyValuer interface {
KeyValues() []interface{}
}
type keyValuerBehavior struct {
keyvals []interface{}
}
func (err *keyValuerBehavior) KeyValues() []interface{} { return err.keyvals }
// WithKeyValues wraps an error with some key values.
func WithKeyValues(err error, keyvals ...interface{}) error {
return struct {
error
*causerBehavior
*keyValuerBehavior
}{
err,
&causerBehavior{cause: err},
&keyValuerBehavior{keyvals: keyvals},
}
}
// HasKeyValues returns embedded key values from the error.
func HasKeyValues(err error) (keyvals []interface{}, ok bool) {
if foundErr := findBehavior(err, func(err error) bool { _, ok := err.(keyValuer); return ok }); foundErr != nil {
return foundErr.(keyValuer).KeyValues(), true
}
return nil, false
}
type errNotFound interface {
IsErrNotFound()
}
type errNotFoundBehavior struct{}
func (err *errNotFoundBehavior) IsErrNotFound() {}
// WithErrNotFound wraps an error with a behavior indicating that a requested resource was not found.
func WithErrNotFound(err error) error {
return struct {
error
*causerBehavior
*errNotFoundBehavior
}{
err,
&causerBehavior{cause: err},
&errNotFoundBehavior{},
}
}
// IsErrNotFound indicates if some requested resource was not found.
func IsErrNotFound(err error) bool {
if foundErr := findBehavior(err, func(err error) bool { _, ok := err.(errNotFound); return ok }); foundErr != nil {
return true
}
return false
}
type errValidation interface {
IsErrValidation()
}
type errValidationBehavior struct{}
func (err *errValidationBehavior) IsErrValidation() {}
// WithErrValidation wraps an error with a behavior indicating that some user parameters were invalid.
func WithErrValidation(err error) error {
return struct {
error
*causerBehavior
*errValidationBehavior
}{
err,
&causerBehavior{cause: err},
&errValidationBehavior{},
}
}
// IsErrValidation indicates if some requested resource was not found.
func IsErrValidation(err error) bool {
if foundErr := findBehavior(err, func(err error) bool { _, ok := err.(errValidation); return ok }); foundErr != nil {
return true
}
return false
}
type errRetriable interface {
IsErrRetriable()
}
type errRetriableBehavior struct{}
func (err *errRetriableBehavior) IsErrRetriable() {}
// WithErrRetriable wraps an error with a behavior indicating that the failed operation should be retried.
func WithErrRetriable(err error) error {
return struct {
error
*causerBehavior
*errRetriableBehavior
}{
err,
&causerBehavior{cause: err},
&errRetriableBehavior{},
}
}
// IsErrRetriable indicates if some failed operation should be retried.
func IsErrRetriable(err error) bool {
if foundErr := findBehavior(err, func(err error) bool { _, ok := err.(errRetriable); return ok }); foundErr != nil {
return true
}
return false
}