errors.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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 New(status int, msg string, pub string) *Error {
  27. return &Error{
  28. StatusCode: status,
  29. Message: msg,
  30. PublicMessage: pub,
  31. }
  32. }
  33. func NewUnexpected(msg string, skip int) *Error {
  34. return &Error{
  35. StatusCode: 500,
  36. Message: msg,
  37. PublicMessage: "Internal error",
  38. Unexpected: true,
  39. stack: callers(skip + 3),
  40. }
  41. }
  42. func Wrap(err error, skip int) *Error {
  43. if ierr, ok := err.(*Error); ok {
  44. return ierr
  45. }
  46. return NewUnexpected(err.Error(), skip+1)
  47. }
  48. func WrapWithPrefix(err error, skip int, prefix string) *Error {
  49. if ierr, ok := err.(*Error); ok {
  50. newErr := *ierr
  51. newErr.Message = fmt.Sprintf("%s: %s", prefix, ierr.Message)
  52. return &newErr
  53. }
  54. return NewUnexpected(fmt.Sprintf("%s: %s", prefix, err), skip+1)
  55. }
  56. func callers(skip int) []uintptr {
  57. stack := make([]uintptr, 10)
  58. n := runtime.Callers(skip, stack)
  59. return stack[:n]
  60. }
  61. func formatStack(stack []uintptr) string {
  62. lines := make([]string, len(stack))
  63. for i, pc := range stack {
  64. f := runtime.FuncForPC(pc)
  65. file, line := f.FileLine(pc)
  66. lines[i] = fmt.Sprintf("%s:%d %s", file, line, f.Name())
  67. }
  68. return strings.Join(lines, "\n")
  69. }