-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
errors.go
148 lines (125 loc) · 2.27 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
package errors
import (
"errors"
"fmt"
"log"
"runtime"
"github.com/sirupsen/logrus"
)
var Level logrus.Level
type Error struct {
// Op is the operation being performed
// this can be named by convention as packageName.FunctionName
// eg: var op = "errors.E"
// for methods on structs this can be packageName.structName.methodName
Op Op
Kind Kind
Err error
Location ErrLocation
}
type ErrLocation struct {
File string
Line int
}
func (l ErrLocation) String() string {
return fmt.Sprintf("file: %v, line: %v", l.File, l.Line)
}
func (e Error) Unwrap() error {
return e.Err
}
type Unwrapper interface {
Unwrap() error
}
var (
_ error = (*Error)(nil)
_ Unwrapper = (*Error)(nil)
)
func (e *Error) Error() string {
return e.Err.Error()
}
var _ error = (*Error)(nil)
type Op string
type Kind uint16
type HRE string
const (
KindOther Kind = iota + 1
KindInternal
KindHasuraAPI
KindBadInput
KindNetwork
)
func (k Kind) String() string {
switch k {
case KindOther:
return "other error"
case KindInternal:
return "internal error"
case KindHasuraAPI:
return "hasura server API error"
case KindBadInput:
return "bad input"
case KindNetwork:
return "network error"
}
return "unknown error kind"
}
func E(op Op, args ...interface{}) error {
_, file, line, _ := runtime.Caller(1)
e := &Error{
Op: op,
Location: ErrLocation{
File: file,
Line: line,
},
}
for _, arg := range args {
switch arg := arg.(type) {
case Kind:
e.Kind = arg
case error:
e.Err = arg
case string:
e.Err = errors.New(arg)
default:
log.Printf("errors.E: bad call from %s:%d:%v: %v", file, line, op, args)
}
}
return e
}
func IsKind(want Kind, err error) bool {
got := GetKind(err)
return got == want
}
func Ops(err *Error) []Op {
ops := []Op{err.Op}
for {
var embeddedErr *Error
if !errors.As(err.Err, &embeddedErr) {
break
}
ops = append(ops, embeddedErr.Op)
err = embeddedErr
}
return ops
}
func GetLocation(err error) ErrLocation {
var prevErr *Error
for {
var e *Error
if !errors.As(err, &e) {
return prevErr.Location
}
prevErr = e
err = e.Err
}
}
func GetKind(err error) Kind {
var e *Error
if !errors.As(err, &e) {
return KindOther
}
if e.Kind != 0 {
return e.Kind
}
return GetKind(e.Err)
}