1
0

error.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package honeybadger
  2. import (
  3. "fmt"
  4. "reflect"
  5. "runtime"
  6. "strconv"
  7. )
  8. const maxFrames = 20
  9. // Frame represent a stack frame inside of a Honeybadger backtrace.
  10. type Frame struct {
  11. Number string `json:"number"`
  12. File string `json:"file"`
  13. Method string `json:"method"`
  14. }
  15. // Error provides more structured information about a Go error.
  16. type Error struct {
  17. err interface{}
  18. Message string
  19. Class string
  20. Stack []*Frame
  21. }
  22. func (e Error) Error() string {
  23. return e.Message
  24. }
  25. func NewError(msg interface{}) Error {
  26. return newError(msg, 2)
  27. }
  28. func newError(thing interface{}, stackOffset int) Error {
  29. var err error
  30. switch t := thing.(type) {
  31. case Error:
  32. return t
  33. case error:
  34. err = t
  35. default:
  36. err = fmt.Errorf("%v", t)
  37. }
  38. return Error{
  39. err: err,
  40. Message: err.Error(),
  41. Class: reflect.TypeOf(err).String(),
  42. Stack: generateStack(stackOffset),
  43. }
  44. }
  45. func generateStack(offset int) (frames []*Frame) {
  46. stack := make([]uintptr, maxFrames)
  47. length := runtime.Callers(2+offset, stack[:])
  48. for _, pc := range stack[:length] {
  49. f := runtime.FuncForPC(pc)
  50. if f == nil {
  51. continue
  52. }
  53. file, line := f.FileLine(pc)
  54. frame := &Frame{
  55. File: file,
  56. Number: strconv.Itoa(line),
  57. Method: f.Name(),
  58. }
  59. frames = append(frames, frame)
  60. }
  61. return
  62. }