gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

error.go (5087B)


      1 // Package errors provides errors that have stack-traces.
      2 //
      3 // This is particularly useful when you want to understand the
      4 // state of execution when an error was returned unexpectedly.
      5 //
      6 // It provides the type *Error which implements the standard
      7 // golang error interface, so you can use this library interchangably
      8 // with code that is expecting a normal error return.
      9 //
     10 // For example:
     11 //
     12 //  package crashy
     13 //
     14 //  import "github.com/go-errors/errors"
     15 //
     16 //  var Crashed = errors.Errorf("oh dear")
     17 //
     18 //  func Crash() error {
     19 //      return errors.New(Crashed)
     20 //  }
     21 //
     22 // This can be called as follows:
     23 //
     24 //  package main
     25 //
     26 //  import (
     27 //      "crashy"
     28 //      "fmt"
     29 //      "github.com/go-errors/errors"
     30 //  )
     31 //
     32 //  func main() {
     33 //      err := crashy.Crash()
     34 //      if err != nil {
     35 //          if errors.Is(err, crashy.Crashed) {
     36 //              fmt.Println(err.(*errors.Error).ErrorStack())
     37 //          } else {
     38 //              panic(err)
     39 //          }
     40 //      }
     41 //  }
     42 //
     43 // This package was original written to allow reporting to Bugsnag,
     44 // but after I found similar packages by Facebook and Dropbox, it
     45 // was moved to one canonical location so everyone can benefit.
     46 package errors
     47 
     48 import (
     49 	"bytes"
     50 	"fmt"
     51 	"reflect"
     52 	"runtime"
     53 )
     54 
     55 // The maximum number of stackframes on any error.
     56 var MaxStackDepth = 50
     57 
     58 // Error is an error with an attached stacktrace. It can be used
     59 // wherever the builtin error interface is expected.
     60 type Error struct {
     61 	Err    error
     62 	stack  []uintptr
     63 	frames []StackFrame
     64 	prefix string
     65 }
     66 
     67 // New makes an Error from the given value. If that value is already an
     68 // error then it will be used directly, if not, it will be passed to
     69 // fmt.Errorf("%v"). The stacktrace will point to the line of code that
     70 // called New.
     71 func New(e interface{}) *Error {
     72 	var err error
     73 
     74 	switch e := e.(type) {
     75 	case error:
     76 		err = e
     77 	default:
     78 		err = fmt.Errorf("%v", e)
     79 	}
     80 
     81 	stack := make([]uintptr, MaxStackDepth)
     82 	length := runtime.Callers(2, stack[:])
     83 	return &Error{
     84 		Err:   err,
     85 		stack: stack[:length],
     86 	}
     87 }
     88 
     89 // Wrap makes an Error from the given value. If that value is already an
     90 // error then it will be used directly, if not, it will be passed to
     91 // fmt.Errorf("%v"). The skip parameter indicates how far up the stack
     92 // to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
     93 func Wrap(e interface{}, skip int) *Error {
     94 	if e == nil {
     95 		return nil
     96 	}
     97 
     98 	var err error
     99 
    100 	switch e := e.(type) {
    101 	case *Error:
    102 		return e
    103 	case error:
    104 		err = e
    105 	default:
    106 		err = fmt.Errorf("%v", e)
    107 	}
    108 
    109 	stack := make([]uintptr, MaxStackDepth)
    110 	length := runtime.Callers(2+skip, stack[:])
    111 	return &Error{
    112 		Err:   err,
    113 		stack: stack[:length],
    114 	}
    115 }
    116 
    117 // WrapPrefix makes an Error from the given value. If that value is already an
    118 // error then it will be used directly, if not, it will be passed to
    119 // fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the
    120 // error message when calling Error(). The skip parameter indicates how far
    121 // up the stack to start the stacktrace. 0 is from the current call,
    122 // 1 from its caller, etc.
    123 func WrapPrefix(e interface{}, prefix string, skip int) *Error {
    124 	if e == nil {
    125 		return nil
    126 	}
    127 
    128 	err := Wrap(e, 1+skip)
    129 
    130 	if err.prefix != "" {
    131 		prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
    132 	}
    133 
    134 	return &Error{
    135 		Err:    err.Err,
    136 		stack:  err.stack,
    137 		prefix: prefix,
    138 	}
    139 
    140 }
    141 
    142 // Errorf creates a new error with the given message. You can use it
    143 // as a drop-in replacement for fmt.Errorf() to provide descriptive
    144 // errors in return values.
    145 func Errorf(format string, a ...interface{}) *Error {
    146 	return Wrap(fmt.Errorf(format, a...), 1)
    147 }
    148 
    149 // Error returns the underlying error's message.
    150 func (err *Error) Error() string {
    151 
    152 	msg := err.Err.Error()
    153 	if err.prefix != "" {
    154 		msg = fmt.Sprintf("%s: %s", err.prefix, msg)
    155 	}
    156 
    157 	return msg
    158 }
    159 
    160 // Stack returns the callstack formatted the same way that go does
    161 // in runtime/debug.Stack()
    162 func (err *Error) Stack() []byte {
    163 	buf := bytes.Buffer{}
    164 
    165 	for _, frame := range err.StackFrames() {
    166 		buf.WriteString(frame.String())
    167 	}
    168 
    169 	return buf.Bytes()
    170 }
    171 
    172 // Callers satisfies the bugsnag ErrorWithCallerS() interface
    173 // so that the stack can be read out.
    174 func (err *Error) Callers() []uintptr {
    175 	return err.stack
    176 }
    177 
    178 // ErrorStack returns a string that contains both the
    179 // error message and the callstack.
    180 func (err *Error) ErrorStack() string {
    181 	return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
    182 }
    183 
    184 // StackFrames returns an array of frames containing information about the
    185 // stack.
    186 func (err *Error) StackFrames() []StackFrame {
    187 	if err.frames == nil {
    188 		err.frames = make([]StackFrame, len(err.stack))
    189 
    190 		for i, pc := range err.stack {
    191 			err.frames[i] = NewStackFrame(pc)
    192 		}
    193 	}
    194 
    195 	return err.frames
    196 }
    197 
    198 // TypeName returns the type this error. e.g. *errors.stringError.
    199 func (err *Error) TypeName() string {
    200 	if _, ok := err.Err.(uncaughtPanic); ok {
    201 		return "panic"
    202 	}
    203 	return reflect.TypeOf(err.Err).String()
    204 }
    205 
    206 // Return the wrapped error (implements api for As function).
    207 func (err *Error) Unwrap() error {
    208 	return err.Err
    209 }