errors.go

  1// 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}