errors.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package ierrors
  2. import (
  3. "fmt"
  4. "runtime"
  5. "strings"
  6. )
  7. type Error struct {
  8. StatusCode int
  9. Message string
  10. PublicMessage string
  11. Unexpected bool
  12. stack []uintptr
  13. }
  14. func (e *Error) Error() string {
  15. return e.Message
  16. }
  17. func (e *Error) FormatStack() string {
  18. if e.stack == nil {
  19. return ""
  20. }
  21. return formatStack(e.stack)
  22. }
  23. func (e *Error) StackTrace() []uintptr {
  24. return e.stack
  25. }
  26. func (e *Error) SetUnexpected(u bool) *Error {
  27. e.Unexpected = u
  28. return e
  29. }
  30. func New(status int, msg string, pub string) *Error {
  31. return &Error{
  32. StatusCode: status,
  33. Message: msg,
  34. PublicMessage: pub,
  35. }
  36. }
  37. func NewUnexpected(msg string, skip int) *Error {
  38. return &Error{
  39. StatusCode: 500,
  40. Message: msg,
  41. PublicMessage: "Internal error",
  42. Unexpected: true,
  43. stack: callers(skip + 3),
  44. }
  45. }
  46. func Wrap(err error, skip int) *Error {
  47. if ierr, ok := err.(*Error); ok {
  48. return ierr
  49. }
  50. return NewUnexpected(err.Error(), skip+1)
  51. }
  52. func WrapWithMessage(err error, skip int, msg string) *Error {
  53. if ierr, ok := err.(*Error); ok {
  54. newErr := *ierr
  55. ierr.Message = msg
  56. return &newErr
  57. }
  58. return NewUnexpected(err.Error(), skip+1)
  59. }
  60. func callers(skip int) []uintptr {
  61. stack := make([]uintptr, 10)
  62. n := runtime.Callers(skip, stack)
  63. return stack[:n]
  64. }
  65. func formatStack(stack []uintptr) string {
  66. lines := make([]string, len(stack))
  67. for i, pc := range stack {
  68. f := runtime.FuncForPC(pc)
  69. file, line := f.FileLine(pc)
  70. lines[i] = fmt.Sprintf("%s:%d %s", file, line, f.Name())
  71. }
  72. return strings.Join(lines, "\n")
  73. }
  74. func StatusCode(err error) int {
  75. if ierr, ok := err.(*Error); ok {
  76. return ierr.StatusCode
  77. }
  78. return 0
  79. }