...

Source file src/github.com/goph/emperror/wrap.go

Documentation: github.com/goph/emperror

     1  package emperror
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"runtime"
     7  
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  func callers() []uintptr {
    12  	const depth = 32
    13  	var pcs [depth]uintptr
    14  
    15  	n := runtime.Callers(3, pcs[:])
    16  
    17  	return pcs[0:n]
    18  }
    19  
    20  type wrappedError struct {
    21  	err   error
    22  	stack []uintptr
    23  }
    24  
    25  func (e *wrappedError) Error() string {
    26  	return e.err.Error()
    27  }
    28  
    29  func (e *wrappedError) Cause() error {
    30  	return e.err
    31  }
    32  
    33  func (e *wrappedError) StackTrace() errors.StackTrace {
    34  	f := make([]errors.Frame, len(e.stack))
    35  
    36  	for i := 0; i < len(f); i++ {
    37  		f[i] = errors.Frame((e.stack)[i])
    38  	}
    39  
    40  	return f
    41  }
    42  
    43  func (e *wrappedError) Format(s fmt.State, verb rune) {
    44  	switch verb {
    45  	case 'v':
    46  		if s.Flag('+') {
    47  			_, _ = fmt.Fprintf(s, "%+v", e.Cause())
    48  
    49  			for _, pc := range e.stack {
    50  				f := errors.Frame(pc)
    51  				_, _ = fmt.Fprintf(s, "\n%+v", f)
    52  			}
    53  
    54  			return
    55  		}
    56  
    57  		fallthrough
    58  
    59  	case 's':
    60  		_, _ = io.WriteString(s, e.Error())
    61  
    62  	case 'q':
    63  		_, _ = fmt.Fprintf(s, "%q", e.Error())
    64  	}
    65  }
    66  
    67  // Wrap returns an error annotating err with a stack trace
    68  // at the point Wrap is called (if there is none attached to the error yet), and the supplied message.
    69  // If err is nil, Wrap returns nil.
    70  //
    71  // Note: do not use this method when passing errors between goroutines.
    72  func Wrap(err error, message string) error {
    73  	if err == nil {
    74  		return nil
    75  	}
    76  
    77  	_, ok := getStackTracer(err)
    78  
    79  	err = errors.WithMessage(err, message)
    80  
    81  	// There is no stack trace in the error, so attach it here
    82  	if !ok {
    83  		err = &wrappedError{
    84  			err:   err,
    85  			stack: callers(),
    86  		}
    87  	}
    88  
    89  	return err
    90  }
    91  
    92  // Wrapf returns an error annotating err with a stack trace
    93  // at the point Wrapf is call (if there is none attached to the error yet), and the format specifier.
    94  // If err is nil, Wrapf returns nil.
    95  //
    96  // Note: do not use this method when passing errors between goroutines.
    97  func Wrapf(err error, format string, args ...interface{}) error {
    98  	if err == nil {
    99  		return nil
   100  	}
   101  
   102  	_, ok := getStackTracer(err)
   103  
   104  	err = errors.WithMessage(err, fmt.Sprintf(format, args...))
   105  
   106  	// There is no stack trace in the error, so attach it here
   107  	if !ok {
   108  		err = &wrappedError{
   109  			err:   err,
   110  			stack: callers(),
   111  		}
   112  	}
   113  
   114  	return err
   115  }
   116  

View as plain text