errors.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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 WrapWithPrefix(err error, skip int, prefix string) *Error {
  53. if ierr, ok := err.(*Error); ok {
  54. newErr := *ierr
  55. newErr.Message = fmt.Sprintf("%s: %s", prefix, ierr.Message)
  56. return &newErr
  57. }
  58. return NewUnexpected(fmt.Sprintf("%s: %s", prefix, err), 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. }