-
Notifications
You must be signed in to change notification settings - Fork 1
/
errors.go
114 lines (99 loc) · 3.18 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
package errors
// New creates a new error.
func New(msg string, opts ...any) error {
passedOpts := make([]any, 1, len(opts)+1)
passedOpts[0] = msg
passedOpts = append(passedOpts, opts...)
return newE(passedOpts...)
}
// Wrap wraps the provided error and includes any additional options on this
// entry of the error. Note, a msg is not required. A new stack frame will
// be captured when calling Wrap. It is useful for that alone. This function
// will not wrap a nil error, rather, it'll return with a nil.
func Wrap(err error, opts ...any) error {
if err == nil {
return nil
}
passedOpts := make([]any, 1, len(opts)+1)
passedOpts[0] = err
passedOpts = append(passedOpts, opts...)
return newE(passedOpts...)
}
// Join returns a new multi error.
//
// TODO:
// - play with Join(opts ...any) and Join(errs []error, opts ...any) sigs
// and ask for feedback regarding tradeoffs with type safety of first arg.
// As of writing some tests, I kind of dig the loose Join(opts ...any).
func Join(opts ...any) error {
return newJoinE(opts...)
}
// Disjoin separates joined errors.
func Disjoin(err error) []error {
if err == nil {
return nil
}
if stdJoin, ok := err.(interface{ Unwrap() []error }); ok {
return stdJoin.Unwrap()
}
if ej, ok := err.(*joinE); ok {
return ej.errs
}
return nil
}
// Fields returns logging fields for a given error.
func Fields(err error) []any {
if err == nil {
return nil
}
fielder, ok := err.(interface{ Fields() []any })
if !ok {
return nil
}
return fielder.Fields()
}
// StackTrace returns the StackFrames for an error. See StackFrames for more info.
// TODO:
// 1. make this more robust with Is
// 2. determine if its even worth exposing an accessor for this private method
// 3. allow for StackTraces() to accommodate joined errors, perhaps returning a map[string]StackFrames
// or some graph representation would be awesome.
func StackTrace(err error) StackFrames {
ee, ok := err.(interface{ stackTrace() StackFrames })
if !ok {
return nil
}
return ee.stackTrace()
}
// V returns a typed value for the kvs of an error. Type conversion
// can be used to convert the output value. We do not distinguish
// between a purposeful <nil> value and key not found. With the
// single return param, we can do the following to convert it to a
// more specific type:
//
// err := errors.New("simple msg", errors.KVs("int", 1))
// i, ok := errors.V(err, "int).(int)
//
// Note: this will take the first matching key. If you are interested
// in obtaining a key's value from a wrapped error collides with a
// parent's key value, then you can manually unwrap the error and call V
// on it to skip the parent field.
//
// TODO:
// - food for thought, we could change the V funcs signature
// to allow for a generic type to be provided, however... it
// feels both premature and limiting in the event you don't
// care about the type. If we get an ask for that, we can provide
// guidance for this via the comment above and perhaps some example
// code.
func V(err error, key string) any {
if err == nil {
return nil
}
fielder, ok := err.(interface{ V(key string) (any, bool) })
if !ok {
return nil
}
raw, _ := fielder.V(key)
return raw
}