blob: 842ee80456dbaab024d2a0f1ca524f7b7c5f241a [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Package errors provides simple error handling primitives.
2//
3// The traditional error handling idiom in Go is roughly akin to
4//
5// if err != nil {
6// return err
7// }
8//
9// which applied recursively up the call stack results in error reports
10// without context or debugging information. The errors package allows
11// programmers to add context to the failure path in their code in a way
12// that does not destroy the original value of the error.
13//
14// Adding context to an error
15//
16// The errors.Wrap function returns a new error that adds context to the
17// original error by recording a stack trace at the point Wrap is called,
18// and the supplied message. For example
19//
20// _, err := ioutil.ReadAll(r)
21// if err != nil {
22// return errors.Wrap(err, "read failed")
23// }
24//
25// If additional control is required the errors.WithStack and errors.WithMessage
26// functions destructure errors.Wrap into its component operations of annotating
27// an error with a stack trace and an a message, respectively.
28//
29// Retrieving the cause of an error
30//
31// Using errors.Wrap constructs a stack of errors, adding context to the
32// preceding error. Depending on the nature of the error it may be necessary
33// to reverse the operation of errors.Wrap to retrieve the original error
34// for inspection. Any error value which implements this interface
35//
36// type causer interface {
37// Cause() error
38// }
39//
40// can be inspected by errors.Cause. errors.Cause will recursively retrieve
41// the topmost error which does not implement causer, which is assumed to be
42// the original cause. For example:
43//
44// switch err := errors.Cause(err).(type) {
45// case *MyError:
46// // handle specifically
47// default:
48// // unknown error
49// }
50//
51// causer interface is not exported by this package, but is considered a part
52// of stable public API.
53//
54// Formatted printing of errors
55//
56// All error values returned from this package implement fmt.Formatter and can
57// be formatted by the fmt package. The following verbs are supported
58//
59// %s print the error. If the error has a Cause it will be
60// printed recursively
61// %v see %s
62// %+v extended format. Each Frame of the error's StackTrace will
63// be printed in detail.
64//
65// Retrieving the stack trace of an error or wrapper
66//
67// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
68// invoked. This information can be retrieved with the following interface.
69//
70// type stackTracer interface {
71// StackTrace() errors.StackTrace
72// }
73//
74// Where errors.StackTrace is defined as
75//
76// type StackTrace []Frame
77//
78// The Frame type represents a call site in the stack trace. Frame supports
79// the fmt.Formatter interface that can be used for printing information about
80// the stack trace of this error. For example:
81//
82// if err, ok := err.(stackTracer); ok {
83// for _, f := range err.StackTrace() {
84// fmt.Printf("%+s:%d", f)
85// }
86// }
87//
88// stackTracer interface is not exported by this package, but is considered a part
89// of stable public API.
90//
91// See the documentation for Frame.Format for more details.
92package errors
93
94import (
95 "fmt"
96 "io"
97)
98
99// New returns an error with the supplied message.
100// New also records the stack trace at the point it was called.
101func New(message string) error {
102 return &fundamental{
103 msg: message,
104 stack: callers(),
105 }
106}
107
108// Errorf formats according to a format specifier and returns the string
109// as a value that satisfies error.
110// Errorf also records the stack trace at the point it was called.
111func Errorf(format string, args ...interface{}) error {
112 return &fundamental{
113 msg: fmt.Sprintf(format, args...),
114 stack: callers(),
115 }
116}
117
118// fundamental is an error that has a message and a stack, but no caller.
119type fundamental struct {
120 msg string
121 *stack
122}
123
124func (f *fundamental) Error() string { return f.msg }
125
126func (f *fundamental) Format(s fmt.State, verb rune) {
127 switch verb {
128 case 'v':
129 if s.Flag('+') {
130 io.WriteString(s, f.msg)
131 f.stack.Format(s, verb)
132 return
133 }
134 fallthrough
135 case 's':
136 io.WriteString(s, f.msg)
137 case 'q':
138 fmt.Fprintf(s, "%q", f.msg)
139 }
140}
141
142// WithStack annotates err with a stack trace at the point WithStack was called.
143// If err is nil, WithStack returns nil.
144func WithStack(err error) error {
145 if err == nil {
146 return nil
147 }
148 return &withStack{
149 err,
150 callers(),
151 }
152}
153
154type withStack struct {
155 error
156 *stack
157}
158
159func (w *withStack) Cause() error { return w.error }
160
161func (w *withStack) Format(s fmt.State, verb rune) {
162 switch verb {
163 case 'v':
164 if s.Flag('+') {
165 fmt.Fprintf(s, "%+v", w.Cause())
166 w.stack.Format(s, verb)
167 return
168 }
169 fallthrough
170 case 's':
171 io.WriteString(s, w.Error())
172 case 'q':
173 fmt.Fprintf(s, "%q", w.Error())
174 }
175}
176
177// Wrap returns an error annotating err with a stack trace
178// at the point Wrap is called, and the supplied message.
179// If err is nil, Wrap returns nil.
180func Wrap(err error, message string) error {
181 if err == nil {
182 return nil
183 }
184 err = &withMessage{
185 cause: err,
186 msg: message,
187 }
188 return &withStack{
189 err,
190 callers(),
191 }
192}
193
194// Wrapf returns an error annotating err with a stack trace
195// at the point Wrapf is call, and the format specifier.
196// If err is nil, Wrapf returns nil.
197func Wrapf(err error, format string, args ...interface{}) error {
198 if err == nil {
199 return nil
200 }
201 err = &withMessage{
202 cause: err,
203 msg: fmt.Sprintf(format, args...),
204 }
205 return &withStack{
206 err,
207 callers(),
208 }
209}
210
211// WithMessage annotates err with a new message.
212// If err is nil, WithMessage returns nil.
213func WithMessage(err error, message string) error {
214 if err == nil {
215 return nil
216 }
217 return &withMessage{
218 cause: err,
219 msg: message,
220 }
221}
222
223type withMessage struct {
224 cause error
225 msg string
226}
227
228func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
229func (w *withMessage) Cause() error { return w.cause }
230
231func (w *withMessage) Format(s fmt.State, verb rune) {
232 switch verb {
233 case 'v':
234 if s.Flag('+') {
235 fmt.Fprintf(s, "%+v\n", w.Cause())
236 io.WriteString(s, w.msg)
237 return
238 }
239 fallthrough
240 case 's', 'q':
241 io.WriteString(s, w.Error())
242 }
243}
244
245// Cause returns the underlying cause of the error, if possible.
246// An error value has a cause if it implements the following
247// interface:
248//
249// type causer interface {
250// Cause() error
251// }
252//
253// If the error does not implement Cause, the original error will
254// be returned. If the error is nil, nil will be returned without further
255// investigation.
256func Cause(err error) error {
257 type causer interface {
258 Cause() error
259 }
260
261 for err != nil {
262 cause, ok := err.(causer)
263 if !ok {
264 break
265 }
266 err = cause.Cause()
267 }
268 return err
269}