errors.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Package errors implements functions to manipulate errors.
  2. package errors
  3. import (
  4. "fmt"
  5. "io"
  6. "os"
  7. "runtime"
  8. "strings"
  9. )
  10. type loc uintptr
  11. func (l loc) Location() (string, int) {
  12. pc := uintptr(l)
  13. fn := runtime.FuncForPC(pc)
  14. if fn == nil {
  15. return "unknown", 0
  16. }
  17. _, prefix, _, _ := runtime.Caller(0)
  18. file, line := fn.FileLine(pc)
  19. if i := strings.LastIndex(prefix, "github.com/pkg/errors"); i > 0 {
  20. file = file[i:]
  21. }
  22. return file, line
  23. }
  24. // New returns an error that formats as the given text.
  25. func New(text string) error {
  26. return struct {
  27. error
  28. loc
  29. }{
  30. fmt.Errorf(text),
  31. loc(pc()),
  32. }
  33. }
  34. type e struct {
  35. cause error
  36. message string
  37. loc
  38. }
  39. func (e *e) Error() string {
  40. return e.message + ": " + e.cause.Error()
  41. }
  42. func (e *e) Cause() error {
  43. return e.cause
  44. }
  45. // Wrap returns an error annotating the cause with message.
  46. // If cause is nil, Wrap returns nil.
  47. func Wrap(cause error, message string) error {
  48. if cause == nil {
  49. return nil
  50. }
  51. return &e{
  52. cause: cause,
  53. message: message,
  54. loc: loc(pc()),
  55. }
  56. }
  57. type causer interface {
  58. Cause() error
  59. }
  60. // Cause returns the underlying cause of the error, if possible.
  61. // An error value has a cause if it implements the following
  62. // interface:
  63. //
  64. // type Causer interface {
  65. // Cause() error
  66. // }
  67. //
  68. // If the error does not implement Cause, the original error will
  69. // be returned. If the error is nil, nil will be returned without further
  70. // investigation.
  71. func Cause(err error) error {
  72. for err != nil {
  73. cause, ok := err.(causer)
  74. if !ok {
  75. break
  76. }
  77. err = cause.Cause()
  78. }
  79. return err
  80. }
  81. type locationer interface {
  82. Location() (string, int)
  83. }
  84. // Print prints the error to Stderr.
  85. // If the error implements the Causer interface described in Cause
  86. // Print will recurse into the error's cause.
  87. // If the error implements the inteface:
  88. //
  89. // type Location interface {
  90. // Location() (file string, line int)
  91. // }
  92. //
  93. // Print will also print the file and line of the error.
  94. func Print(err error) {
  95. Fprint(os.Stderr, err)
  96. }
  97. // Fprint prints the error to the supplied writer.
  98. // The format of the output is the same as Print.
  99. // If err is nil, nothing is printed.
  100. func Fprint(w io.Writer, err error) {
  101. for err != nil {
  102. location, ok := err.(locationer)
  103. if ok {
  104. file, line := location.Location()
  105. fmt.Fprintf(w, "%s:%d: ", file, line)
  106. }
  107. switch err := err.(type) {
  108. case *e:
  109. fmt.Fprintln(w, err.message)
  110. default:
  111. fmt.Fprintln(w, err.Error())
  112. }
  113. cause, ok := err.(causer)
  114. if !ok {
  115. break
  116. }
  117. err = cause.Cause()
  118. }
  119. }
  120. func pc() uintptr {
  121. pc, _, _, _ := runtime.Caller(2)
  122. return pc
  123. }