github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/juju/errors/error.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package errors
     5  
     6  import (
     7  	"fmt"
     8  	"reflect"
     9  	"runtime"
    10  )
    11  
    12  // Err holds a description of an error along with information about
    13  // where the error was created.
    14  //
    15  // It may be embedded in custom error types to add extra information that
    16  // this errors package can understand.
    17  type Err struct {
    18  	// message holds an annotation of the error.
    19  	message string
    20  
    21  	// cause holds the cause of the error as returned
    22  	// by the Cause method.
    23  	cause error
    24  
    25  	// previous holds the previous error in the error stack, if any.
    26  	previous error
    27  
    28  	// file and line hold the source code location where the error was
    29  	// created.
    30  	file string
    31  	line int
    32  }
    33  
    34  // NewErr is used to return an Err for the purpose of embedding in other
    35  // structures.  The location is not specified, and needs to be set with a call
    36  // to SetLocation.
    37  //
    38  // For example:
    39  //     type FooError struct {
    40  //         errors.Err
    41  //         code int
    42  //     }
    43  //
    44  //     func NewFooError(code int) error {
    45  //         err := &FooError{errors.NewErr("foo"), code}
    46  //         err.SetLocation(1)
    47  //         return err
    48  //     }
    49  func NewErr(format string, args ...interface{}) Err {
    50  	return Err{
    51  		message: fmt.Sprintf(format, args...),
    52  	}
    53  }
    54  
    55  // NewErrWithCause is used to return an Err with case by other error for the purpose of embedding in other
    56  // structures. The location is not specified, and needs to be set with a call
    57  // to SetLocation.
    58  //
    59  // For example:
    60  //     type FooError struct {
    61  //         errors.Err
    62  //         code int
    63  //     }
    64  //
    65  //     func (e *FooError) Annotate(format string, args ...interface{}) error {
    66  //         err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
    67  //         err.SetLocation(1)
    68  //         return err
    69  //     })
    70  func NewErrWithCause(other error, format string, args ...interface{}) Err {
    71  	return Err{
    72  		message:  fmt.Sprintf(format, args...),
    73  		cause:    Cause(other),
    74  		previous: other,
    75  	}
    76  }
    77  
    78  // Location is the file and line of where the error was most recently
    79  // created or annotated.
    80  func (e *Err) Location() (filename string, line int) {
    81  	return e.file, e.line
    82  }
    83  
    84  // Underlying returns the previous error in the error stack, if any. A client
    85  // should not ever really call this method.  It is used to build the error
    86  // stack and should not be introspected by client calls.  Or more
    87  // specifically, clients should not depend on anything but the `Cause` of an
    88  // error.
    89  func (e *Err) Underlying() error {
    90  	return e.previous
    91  }
    92  
    93  // The Cause of an error is the most recent error in the error stack that
    94  // meets one of these criteria: the original error that was raised; the new
    95  // error that was passed into the Wrap function; the most recently masked
    96  // error; or nil if the error itself is considered the Cause.  Normally this
    97  // method is not invoked directly, but instead through the Cause stand alone
    98  // function.
    99  func (e *Err) Cause() error {
   100  	return e.cause
   101  }
   102  
   103  // Message returns the message stored with the most recent location. This is
   104  // the empty string if the most recent call was Trace, or the message stored
   105  // with Annotate or Mask.
   106  func (e *Err) Message() string {
   107  	return e.message
   108  }
   109  
   110  // Error implements error.Error.
   111  func (e *Err) Error() string {
   112  	// We want to walk up the stack of errors showing the annotations
   113  	// as long as the cause is the same.
   114  	err := e.previous
   115  	if !sameError(Cause(err), e.cause) && e.cause != nil {
   116  		err = e.cause
   117  	}
   118  	switch {
   119  	case err == nil:
   120  		return e.message
   121  	case e.message == "":
   122  		return err.Error()
   123  	}
   124  	return fmt.Sprintf("%s: %v", e.message, err)
   125  }
   126  
   127  // SetLocation records the source location of the error at callDepth stack
   128  // frames above the call.
   129  func (e *Err) SetLocation(callDepth int) {
   130  	_, file, line, _ := runtime.Caller(callDepth + 1)
   131  	e.file = trimGoPath(file)
   132  	e.line = line
   133  }
   134  
   135  // StackTrace returns one string for each location recorded in the stack of
   136  // errors. The first value is the originating error, with a line for each
   137  // other annotation or tracing of the error.
   138  func (e *Err) StackTrace() []string {
   139  	return errorStack(e)
   140  }
   141  
   142  // Ideally we'd have a way to check identity, but deep equals will do.
   143  func sameError(e1, e2 error) bool {
   144  	return reflect.DeepEqual(e1, e2)
   145  }