| // Package errors provides simple error handling primitives. |
| // |
| // The traditional error handling idiom in Go is roughly akin to |
| // |
| // if err != nil { |
| // return err |
| // } |
| // |
| // which applied recursively up the call stack results in error reports |
| // without context or debugging information. The errors package allows |
| // programmers to add context to the failure path in their code in a way |
| // that does not destroy the original value of the error. |
| // |
| // Adding context to an error |
| // |
| // The errors.Wrap function returns a new error that adds context to the |
| // original error. For example |
| // |
| // _, err := ioutil.ReadAll(r) |
| // if err != nil { |
| // return errors.Wrap(err, "read failed") |
| // } |
| // |
| // Retrieving the cause of an error |
| // |
| // Using errors.Wrap constructs a stack of errors, adding context to the |
| // preceding error. Depending on the nature of the error it may be necessary |
| // to reverse the operation of errors.Wrap to retrieve the original error |
| // for inspection. Any error value which implements this interface |
| // |
| // type Causer interface { |
| // Cause() error |
| // } |
| // |
| // can be inspected by errors.Cause. errors.Cause will recursively retrieve |
| // the topmost error which does not implement causer, which is assumed to be |
| // the original cause. For example: |
| // |
| // switch err := errors.Cause(err).(type) { |
| // case *MyError: |
| // // handle specifically |
| // default: |
| // // unknown error |
| // } |
| // |
| // Retrieving the stack trace of an error or wrapper |
| // |
| // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are |
| // invoked. This information can be retrieved with the following interface. |
| // |
| // type Stacktrace interface { |
| // Stacktrace() []Frame |
| // } |
| package errors |
| |
| import ( |
| "errors" |
| "fmt" |
| "io" |
| ) |
| |
| // New returns an error that formats as the given text. |
| func New(text string) error { |
| return struct { |
| error |
| *stack |
| }{ |
| errors.New(text), |
| callers(), |
| } |
| } |
| |
| type cause struct { |
| cause error |
| message string |
| } |
| |
| func (c cause) Error() string { return c.Message() + ": " + c.Cause().Error() } |
| func (c cause) Cause() error { return c.cause } |
| func (c cause) Message() string { return c.message } |
| |
| // Errorf formats according to a format specifier and returns the string |
| // as a value that satisfies error. |
| func Errorf(format string, args ...interface{}) error { |
| return struct { |
| error |
| *stack |
| }{ |
| fmt.Errorf(format, args...), |
| callers(), |
| } |
| } |
| |
| // Wrap returns an error annotating err with message. |
| // If err is nil, Wrap returns nil. |
| func Wrap(err error, message string) error { |
| if err == nil { |
| return nil |
| } |
| return struct { |
| cause |
| *stack |
| }{ |
| cause{ |
| cause: err, |
| message: message, |
| }, |
| callers(), |
| } |
| } |
| |
| // Wrapf returns an error annotating err with the format specifier. |
| // If err is nil, Wrapf returns nil. |
| func Wrapf(err error, format string, args ...interface{}) error { |
| if err == nil { |
| return nil |
| } |
| return struct { |
| cause |
| *stack |
| }{ |
| cause{ |
| cause: err, |
| message: fmt.Sprintf(format, args...), |
| }, |
| callers(), |
| } |
| } |
| |
| type causer interface { |
| Cause() error |
| } |
| |
| // Cause returns the underlying cause of the error, if possible. |
| // An error value has a cause if it implements the following |
| // interface: |
| // |
| // type Causer interface { |
| // Cause() error |
| // } |
| // |
| // If the error does not implement Cause, the original error will |
| // be returned. If the error is nil, nil will be returned without further |
| // investigation. |
| func Cause(err error) error { |
| for err != nil { |
| cause, ok := err.(causer) |
| if !ok { |
| break |
| } |
| err = cause.Cause() |
| } |
| return err |
| } |
| |
| // Fprint prints the error to the supplied writer. |
| // If the error implements the Causer interface described in Cause |
| // Print will recurse into the error's cause. |
| // If the error implements one of the following interfaces: |
| // |
| // type Stacktrace interface { |
| // Stacktrace() []Frame |
| // } |
| // |
| // type Location interface { |
| // Location() (file string, line int) |
| // } |
| // |
| // Print will also print the file and line of the error. |
| // If err is nil, nothing is printed. |
| // |
| // Deprecated: Fprint will be removed in version 0.7. |
| func Fprint(w io.Writer, err error) { |
| type location interface { |
| Location() (string, int) |
| } |
| type stacktrace interface { |
| Stacktrace() []Frame |
| } |
| type message interface { |
| Message() string |
| } |
| |
| for err != nil { |
| switch err := err.(type) { |
| case stacktrace: |
| frame := err.Stacktrace()[0] |
| fmt.Fprintf(w, "%+s:%d: ", frame, frame) |
| case location: |
| file, line := err.Location() |
| fmt.Fprintf(w, "%s:%d: ", file, line) |
| default: |
| // de nada |
| } |
| switch err := err.(type) { |
| case message: |
| fmt.Fprintln(w, err.Message()) |
| default: |
| fmt.Fprintln(w, err.Error()) |
| } |
| |
| cause, ok := err.(causer) |
| if !ok { |
| break |
| } |
| err = cause.Cause() |
| } |
| } |