-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathxerrors.go
132 lines (122 loc) · 3.25 KB
/
xerrors.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
package xerrors
import (
"fmt"
)
// Wrapper provides context around another error.
type Wrapper interface {
error
Unwrap() error
}
// StackTracer provides a stack trace for an error.
type StackTracer interface {
error
StackTrace() Callers
}
// MultiError is an error that contains multiple errors.
type MultiError interface {
error
Errors() []error
}
// DetailedError provides extended information about an error.
// The ErrorDetails method returns a longer, multi-line description of
// the error. It always ends with a new line.
type DetailedError interface {
error
ErrorDetails() string
}
// messageError is the simplest possible error that contains only
// a string message.
type messageError struct {
msg string
}
// Error implements the error interface.
func (e *messageError) Error() string {
return e.msg
}
// Message creates a simple error with the given message. It does not record
// a stack trace. Each call returns a distinct error value even if the
// message is identical.
//
// This function is intended to create sentinel errors, sometimes referred
// to as "constant errors".
func Message(msg string) error {
return &messageError{msg: msg}
}
// New creates a new error from the given value and records a stack trace at
// the point it was called. If multiple values are provided, then each error
// is wrapped by the previous error. Calling New(a, b, c), where a, b, and c
// are errors, is equivalent to calling New(WithWrapper(WithWrapper(a, b), c)).
//
// This function may be used to:
//
// - Add a stack trace to an error: New(err)
//
// - Create a message error with a stack trace: New("access denied")
//
// - Wrap an error with a message: New("access denied", io.EOF)
//
// - Wrap one error in another: New(ErrAccessDenied, io.EOF)
//
// - Add a message to a sentinel error: New(ErrReadError, "access denied")
//
// Values are converted to errors according to the following rules:
//
// - If a value is an error, it will be used as is.
//
// - If a value is a string, then new error with a given string as a message
// will be created.
//
// - If a value is nil, it will be ignored.
//
// - If a value implements the fmt.Stringer interface, then a String() method
// will be used to create an error.
//
// - For other types the result of fmt.Sprint will be used to create a message
// error.
//
// It is possible to use errors.Is function on returned error to check whether
// an error has been used in the New function.
//
// If the function is called with no arguments or all arguments are nil, it
// returns nil.
//
// To create a simple message error without a stack trace to be used as a
// sentinel error, use the Message function instead.
func New(vals ...interface{}) error {
var errs error
for _, val := range vals {
if val == nil {
continue
}
err := toError(val)
if errs == nil {
errs = err
} else {
errs = &withWrapper{
wrapper: errs,
err: err,
}
}
}
if errs == nil {
return nil
}
return &withStackTrace{
err: errs,
stack: callers(1),
}
}
func toError(val interface{}) error {
var err error
switch typ := val.(type) {
case error:
err = typ
case string:
err = &messageError{msg: typ}
case fmt.Stringer:
err = &messageError{msg: typ.String()}
default:
err = &messageError{msg: fmt.Sprint(val)}
}
return err
}