err.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package errors
  2. import (
  3. "fmt"
  4. "io"
  5. "runtime"
  6. "github.com/pkg/errors"
  7. )
  8. func callers() []uintptr {
  9. var pcs [32]uintptr
  10. l := runtime.Callers(3, pcs[:])
  11. return pcs[:l]
  12. }
  13. // Error a error with caller stack information
  14. type Error interface {
  15. error
  16. t()
  17. }
  18. var _ Error = (*item)(nil)
  19. var _ fmt.Formatter = (*item)(nil)
  20. type item struct {
  21. msg string
  22. stack []uintptr
  23. }
  24. func (i *item) Error() string {
  25. return i.msg
  26. }
  27. func (i *item) t() {}
  28. // Format used by go.uber.org/zap in Verbose
  29. func (i *item) Format(s fmt.State, verb rune) {
  30. _, _ = io.WriteString(s, i.msg)
  31. _, _ = io.WriteString(s, "\n")
  32. for _, pc := range i.stack {
  33. _, _ = fmt.Fprintf(s, "%+v\n", errors.Frame(pc))
  34. }
  35. }
  36. // New create a new error
  37. func New(msg string) Error {
  38. return &item{msg: msg, stack: callers()}
  39. }
  40. // Errorf create a new error
  41. func Errorf(format string, args ...any) Error {
  42. return &item{msg: fmt.Sprintf(format, args...), stack: callers()}
  43. }
  44. // Wrap with some extra message into err
  45. func Wrap(err error, msg string) Error {
  46. if err == nil {
  47. return nil
  48. }
  49. e, ok := err.(*item)
  50. if !ok {
  51. return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()}
  52. }
  53. e.msg = fmt.Sprintf("%s; %s", msg, e.msg)
  54. return e
  55. }
  56. // Wrapf with some extra message into err
  57. func Wrapf(err error, format string, args ...any) Error {
  58. if err == nil {
  59. return nil
  60. }
  61. msg := fmt.Sprintf(format, args...)
  62. e, ok := err.(*item)
  63. if !ok {
  64. return &item{msg: fmt.Sprintf("%s; %s", msg, err.Error()), stack: callers()}
  65. }
  66. e.msg = fmt.Sprintf("%s; %s", msg, e.msg)
  67. return e
  68. }
  69. // WithStack add caller stack information
  70. func WithStack(err error) Error {
  71. if err == nil {
  72. return nil
  73. }
  74. if e, ok := err.(*item); ok {
  75. return e
  76. }
  77. return &item{msg: err.Error(), stack: callers()}
  78. }