error.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Package errors provides errors that have stack-traces.
  2. package errors
  3. import (
  4. "bytes"
  5. "fmt"
  6. "reflect"
  7. "runtime"
  8. )
  9. // The maximum number of stackframes on any error.
  10. var MaxStackDepth = 50
  11. // Error is an error with an attached stacktrace. It can be used
  12. // wherever the builtin error interface is expected.
  13. type Error struct {
  14. Err error
  15. stack []uintptr
  16. frames []StackFrame
  17. }
  18. // ErrorWithCallers allows passing in error objects that
  19. // also have caller information attached.
  20. type ErrorWithCallers interface {
  21. Error() string
  22. Callers() []uintptr
  23. }
  24. // ErrorWithStackFrames allows the stack to be rebuilt from the stack frames, thus
  25. // allowing to use the Error type when the program counter is not available.
  26. type ErrorWithStackFrames interface {
  27. Error() string
  28. StackFrames() []StackFrame
  29. }
  30. // New makes an Error from the given value. If that value is already an
  31. // error then it will be used directly, if not, it will be passed to
  32. // fmt.Errorf("%v"). The skip parameter indicates how far up the stack
  33. // to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
  34. func New(e interface{}, skip int) *Error {
  35. var err error
  36. switch e := e.(type) {
  37. case *Error:
  38. return e
  39. case ErrorWithCallers:
  40. return &Error{
  41. Err: e,
  42. stack: e.Callers(),
  43. }
  44. case ErrorWithStackFrames:
  45. stack := make([]uintptr, len(e.StackFrames()))
  46. for i, frame := range e.StackFrames() {
  47. stack[i] = frame.ProgramCounter
  48. }
  49. return &Error{
  50. Err: e,
  51. stack: stack,
  52. frames: e.StackFrames(),
  53. }
  54. case error:
  55. err = e
  56. default:
  57. err = fmt.Errorf("%v", e)
  58. }
  59. stack := make([]uintptr, MaxStackDepth)
  60. length := runtime.Callers(2+skip, stack[:])
  61. return &Error{
  62. Err: err,
  63. stack: stack[:length],
  64. }
  65. }
  66. // Errorf creates a new error with the given message. You can use it
  67. // as a drop-in replacement for fmt.Errorf() to provide descriptive
  68. // errors in return values.
  69. func Errorf(format string, a ...interface{}) *Error {
  70. return New(fmt.Errorf(format, a...), 1)
  71. }
  72. // Error returns the underlying error's message.
  73. func (err *Error) Error() string {
  74. return err.Err.Error()
  75. }
  76. // Callers returns the raw stack frames as returned by runtime.Callers()
  77. func (err *Error) Callers() []uintptr {
  78. return err.stack[:]
  79. }
  80. // Stack returns the callstack formatted the same way that go does
  81. // in runtime/debug.Stack()
  82. func (err *Error) Stack() []byte {
  83. buf := bytes.Buffer{}
  84. for _, frame := range err.StackFrames() {
  85. buf.WriteString(frame.String())
  86. }
  87. return buf.Bytes()
  88. }
  89. // StackFrames returns an array of frames containing information about the
  90. // stack.
  91. func (err *Error) StackFrames() []StackFrame {
  92. if err.frames == nil {
  93. err.frames = make([]StackFrame, len(err.stack))
  94. for i, pc := range err.stack {
  95. err.frames[i] = NewStackFrame(pc)
  96. }
  97. }
  98. return err.frames
  99. }
  100. // TypeName returns the type this error. e.g. *errors.stringError.
  101. func (err *Error) TypeName() string {
  102. if _, ok := err.Err.(uncaughtPanic); ok {
  103. return "panic"
  104. }
  105. if name := reflect.TypeOf(err.Err).String(); len(name) > 0 {
  106. return name
  107. }
  108. return "error"
  109. }