error.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. import (
  48. "bytes"
  49. baseErrors "errors"
  50. "fmt"
  51. "reflect"
  52. "runtime"
  53. )
  54. // The maximum number of stackframes on any error.
  55. var MaxStackDepth = 50
  56. // Error is an error with an attached stacktrace. It can be used
  57. // wherever the builtin error interface is expected.
  58. type Error struct {
  59. Err error
  60. stack []uintptr
  61. frames []StackFrame
  62. prefix string
  63. }
  64. // New makes an Error from the given value. If that value is already an
  65. // error then it will be used directly, if not, it will be passed to
  66. // fmt.Errorf("%v"). The stacktrace will point to the line of code that
  67. // called New.
  68. func New(e interface{}) *Error {
  69. var err error
  70. switch e := e.(type) {
  71. case error:
  72. err = e
  73. default:
  74. err = fmt.Errorf("%v", e)
  75. }
  76. stack := make([]uintptr, MaxStackDepth)
  77. length := runtime.Callers(2, stack[:])
  78. return &Error{
  79. Err: err,
  80. stack: stack[:length],
  81. }
  82. }
  83. // Wrap makes an Error from the given value. If that value is already an
  84. // error then it will be used directly, if not, it will be passed to
  85. // fmt.Errorf("%v"). The skip parameter indicates how far up the stack
  86. // to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
  87. func Wrap(e interface{}, skip int) *Error {
  88. if e == nil {
  89. return nil
  90. }
  91. var err error
  92. switch e := e.(type) {
  93. case *Error:
  94. return e
  95. case error:
  96. err = e
  97. default:
  98. err = fmt.Errorf("%v", e)
  99. }
  100. stack := make([]uintptr, MaxStackDepth)
  101. length := runtime.Callers(2+skip, stack[:])
  102. return &Error{
  103. Err: err,
  104. stack: stack[:length],
  105. }
  106. }
  107. // WrapPrefix makes an Error from the given value. If that value is already an
  108. // error then it will be used directly, if not, it will be passed to
  109. // fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the
  110. // error message when calling Error(). The skip parameter indicates how far
  111. // up the stack to start the stacktrace. 0 is from the current call,
  112. // 1 from its caller, etc.
  113. func WrapPrefix(e interface{}, prefix string, skip int) *Error {
  114. if e == nil {
  115. return nil
  116. }
  117. err := Wrap(e, 1+skip)
  118. if err.prefix != "" {
  119. prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
  120. }
  121. return &Error{
  122. Err: err.Err,
  123. stack: err.stack,
  124. prefix: prefix,
  125. }
  126. }
  127. // Is detects whether the error is equal to a given error. Errors
  128. // are considered equal by this function if they are matched by errors.Is
  129. // or if their contained errors are matched through errors.Is
  130. func Is(e error, original error) bool {
  131. if baseErrors.Is(e, original) {
  132. return true
  133. }
  134. if e, ok := e.(*Error); ok {
  135. return Is(e.Err, original)
  136. }
  137. if original, ok := original.(*Error); ok {
  138. return Is(e, original.Err)
  139. }
  140. return false
  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. // Error returns the underlying error's message.
  149. func (err *Error) Error() string {
  150. msg := err.Err.Error()
  151. if err.prefix != "" {
  152. msg = fmt.Sprintf("%s: %s", err.prefix, msg)
  153. }
  154. return msg
  155. }
  156. // Stack returns the callstack formatted the same way that go does
  157. // in runtime/debug.Stack()
  158. func (err *Error) Stack() []byte {
  159. buf := bytes.Buffer{}
  160. for _, frame := range err.StackFrames() {
  161. buf.WriteString(frame.String())
  162. }
  163. return buf.Bytes()
  164. }
  165. // Callers satisfies the bugsnag ErrorWithCallerS() interface
  166. // so that the stack can be read out.
  167. func (err *Error) Callers() []uintptr {
  168. return err.stack
  169. }
  170. // ErrorStack returns a string that contains both the
  171. // error message and the callstack.
  172. func (err *Error) ErrorStack() string {
  173. return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
  174. }
  175. // StackFrames returns an array of frames containing information about the
  176. // stack.
  177. func (err *Error) StackFrames() []StackFrame {
  178. if err.frames == nil {
  179. err.frames = make([]StackFrame, len(err.stack))
  180. for i, pc := range err.stack {
  181. err.frames[i] = NewStackFrame(pc)
  182. }
  183. }
  184. return err.frames
  185. }
  186. // TypeName returns the type this error. e.g. *errors.stringError.
  187. func (err *Error) TypeName() string {
  188. if _, ok := err.Err.(uncaughtPanic); ok {
  189. return "panic"
  190. }
  191. return reflect.TypeOf(err.Err).String()
  192. }