error.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright (c) 2017 Uber Technologies, Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. // Package multierr allows combining one or more errors together.
  21. //
  22. // Overview
  23. //
  24. // Errors can be combined with the use of the Combine function.
  25. //
  26. // multierr.Combine(
  27. // reader.Close(),
  28. // writer.Close(),
  29. // conn.Close(),
  30. // )
  31. //
  32. // If only two errors are being combined, the Append function may be used
  33. // instead.
  34. //
  35. // err = multierr.Combine(reader.Close(), writer.Close())
  36. //
  37. // This makes it possible to record resource cleanup failures from deferred
  38. // blocks with the help of named return values.
  39. //
  40. // func sendRequest(req Request) (err error) {
  41. // conn, err := openConnection()
  42. // if err != nil {
  43. // return err
  44. // }
  45. // defer func() {
  46. // err = multierr.Append(err, conn.Close())
  47. // }()
  48. // // ...
  49. // }
  50. //
  51. // The underlying list of errors for a returned error object may be retrieved
  52. // with the Errors function.
  53. //
  54. // errors := multierr.Errors(err)
  55. // if len(errors) > 0 {
  56. // fmt.Println("The following errors occurred:")
  57. // }
  58. //
  59. // Advanced Usage
  60. //
  61. // Errors returned by Combine and Append MAY implement the following
  62. // interface.
  63. //
  64. // type errorGroup interface {
  65. // // Returns a slice containing the underlying list of errors.
  66. // //
  67. // // This slice MUST NOT be modified by the caller.
  68. // Errors() []error
  69. // }
  70. //
  71. // Note that if you need access to list of errors behind a multierr error, you
  72. // should prefer using the Errors function. That said, if you need cheap
  73. // read-only access to the underlying errors slice, you can attempt to cast
  74. // the error to this interface. You MUST handle the failure case gracefully
  75. // because errors returned by Combine and Append are not guaranteed to
  76. // implement this interface.
  77. //
  78. // var errors []error
  79. // group, ok := err.(errorGroup)
  80. // if ok {
  81. // errors = group.Errors()
  82. // } else {
  83. // errors = []error{err}
  84. // }
  85. package multierr // import "go.uber.org/multierr"
  86. import (
  87. "bytes"
  88. "fmt"
  89. "io"
  90. "strings"
  91. "sync"
  92. "go.uber.org/atomic"
  93. )
  94. var (
  95. // Separator for single-line error messages.
  96. _singlelineSeparator = []byte("; ")
  97. _newline = []byte("\n")
  98. // Prefix for multi-line messages
  99. _multilinePrefix = []byte("the following errors occurred:")
  100. // Prefix for the first and following lines of an item in a list of
  101. // multi-line error messages.
  102. //
  103. // For example, if a single item is:
  104. //
  105. // foo
  106. // bar
  107. //
  108. // It will become,
  109. //
  110. // - foo
  111. // bar
  112. _multilineSeparator = []byte("\n - ")
  113. _multilineIndent = []byte(" ")
  114. )
  115. // _bufferPool is a pool of bytes.Buffers.
  116. var _bufferPool = sync.Pool{
  117. New: func() interface{} {
  118. return &bytes.Buffer{}
  119. },
  120. }
  121. type errorGroup interface {
  122. Errors() []error
  123. }
  124. // Errors returns a slice containing zero or more errors that the supplied
  125. // error is composed of. If the error is nil, the returned slice is empty.
  126. //
  127. // err := multierr.Append(r.Close(), w.Close())
  128. // errors := multierr.Errors(err)
  129. //
  130. // If the error is not composed of other errors, the returned slice contains
  131. // just the error that was passed in.
  132. //
  133. // Callers of this function are free to modify the returned slice.
  134. func Errors(err error) []error {
  135. if err == nil {
  136. return nil
  137. }
  138. // Note that we're casting to multiError, not errorGroup. Our contract is
  139. // that returned errors MAY implement errorGroup. Errors, however, only
  140. // has special behavior for multierr-specific error objects.
  141. //
  142. // This behavior can be expanded in the future but I think it's prudent to
  143. // start with as little as possible in terms of contract and possibility
  144. // of misuse.
  145. eg, ok := err.(*multiError)
  146. if !ok {
  147. return []error{err}
  148. }
  149. errors := eg.Errors()
  150. result := make([]error, len(errors))
  151. copy(result, errors)
  152. return result
  153. }
  154. // multiError is an error that holds one or more errors.
  155. //
  156. // An instance of this is guaranteed to be non-empty and flattened. That is,
  157. // none of the errors inside multiError are other multiErrors.
  158. //
  159. // multiError formats to a semi-colon delimited list of error messages with
  160. // %v and with a more readable multi-line format with %+v.
  161. type multiError struct {
  162. copyNeeded atomic.Bool
  163. errors []error
  164. }
  165. var _ errorGroup = (*multiError)(nil)
  166. // Errors returns the list of underlying errors.
  167. //
  168. // This slice MUST NOT be modified.
  169. func (merr *multiError) Errors() []error {
  170. if merr == nil {
  171. return nil
  172. }
  173. return merr.errors
  174. }
  175. func (merr *multiError) Error() string {
  176. if merr == nil {
  177. return ""
  178. }
  179. buff := _bufferPool.Get().(*bytes.Buffer)
  180. buff.Reset()
  181. merr.writeSingleline(buff)
  182. result := buff.String()
  183. _bufferPool.Put(buff)
  184. return result
  185. }
  186. func (merr *multiError) Format(f fmt.State, c rune) {
  187. if c == 'v' && f.Flag('+') {
  188. merr.writeMultiline(f)
  189. } else {
  190. merr.writeSingleline(f)
  191. }
  192. }
  193. func (merr *multiError) writeSingleline(w io.Writer) {
  194. first := true
  195. for _, item := range merr.errors {
  196. if first {
  197. first = false
  198. } else {
  199. w.Write(_singlelineSeparator)
  200. }
  201. io.WriteString(w, item.Error())
  202. }
  203. }
  204. func (merr *multiError) writeMultiline(w io.Writer) {
  205. w.Write(_multilinePrefix)
  206. for _, item := range merr.errors {
  207. w.Write(_multilineSeparator)
  208. writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
  209. }
  210. }
  211. // Writes s to the writer with the given prefix added before each line after
  212. // the first.
  213. func writePrefixLine(w io.Writer, prefix []byte, s string) {
  214. first := true
  215. for len(s) > 0 {
  216. if first {
  217. first = false
  218. } else {
  219. w.Write(prefix)
  220. }
  221. idx := strings.IndexByte(s, '\n')
  222. if idx < 0 {
  223. idx = len(s) - 1
  224. }
  225. io.WriteString(w, s[:idx+1])
  226. s = s[idx+1:]
  227. }
  228. }
  229. type inspectResult struct {
  230. // Number of top-level non-nil errors
  231. Count int
  232. // Total number of errors including multiErrors
  233. Capacity int
  234. // Index of the first non-nil error in the list. Value is meaningless if
  235. // Count is zero.
  236. FirstErrorIdx int
  237. // Whether the list contains at least one multiError
  238. ContainsMultiError bool
  239. }
  240. // Inspects the given slice of errors so that we can efficiently allocate
  241. // space for it.
  242. func inspect(errors []error) (res inspectResult) {
  243. first := true
  244. for i, err := range errors {
  245. if err == nil {
  246. continue
  247. }
  248. res.Count++
  249. if first {
  250. first = false
  251. res.FirstErrorIdx = i
  252. }
  253. if merr, ok := err.(*multiError); ok {
  254. res.Capacity += len(merr.errors)
  255. res.ContainsMultiError = true
  256. } else {
  257. res.Capacity++
  258. }
  259. }
  260. return
  261. }
  262. // fromSlice converts the given list of errors into a single error.
  263. func fromSlice(errors []error) error {
  264. res := inspect(errors)
  265. switch res.Count {
  266. case 0:
  267. return nil
  268. case 1:
  269. // only one non-nil entry
  270. return errors[res.FirstErrorIdx]
  271. case len(errors):
  272. if !res.ContainsMultiError {
  273. // already flat
  274. return &multiError{errors: errors}
  275. }
  276. }
  277. nonNilErrs := make([]error, 0, res.Capacity)
  278. for _, err := range errors[res.FirstErrorIdx:] {
  279. if err == nil {
  280. continue
  281. }
  282. if nested, ok := err.(*multiError); ok {
  283. nonNilErrs = append(nonNilErrs, nested.errors...)
  284. } else {
  285. nonNilErrs = append(nonNilErrs, err)
  286. }
  287. }
  288. return &multiError{errors: nonNilErrs}
  289. }
  290. // Combine combines the passed errors into a single error.
  291. //
  292. // If zero arguments were passed or if all items are nil, a nil error is
  293. // returned.
  294. //
  295. // Combine(nil, nil) // == nil
  296. //
  297. // If only a single error was passed, it is returned as-is.
  298. //
  299. // Combine(err) // == err
  300. //
  301. // Combine skips over nil arguments so this function may be used to combine
  302. // together errors from operations that fail independently of each other.
  303. //
  304. // multierr.Combine(
  305. // reader.Close(),
  306. // writer.Close(),
  307. // pipe.Close(),
  308. // )
  309. //
  310. // If any of the passed errors is a multierr error, it will be flattened along
  311. // with the other errors.
  312. //
  313. // multierr.Combine(multierr.Combine(err1, err2), err3)
  314. // // is the same as
  315. // multierr.Combine(err1, err2, err3)
  316. //
  317. // The returned error formats into a readable multi-line error message if
  318. // formatted with %+v.
  319. //
  320. // fmt.Sprintf("%+v", multierr.Combine(err1, err2))
  321. func Combine(errors ...error) error {
  322. return fromSlice(errors)
  323. }
  324. // Append appends the given errors together. Either value may be nil.
  325. //
  326. // This function is a specialization of Combine for the common case where
  327. // there are only two errors.
  328. //
  329. // err = multierr.Append(reader.Close(), writer.Close())
  330. //
  331. // The following pattern may also be used to record failure of deferred
  332. // operations without losing information about the original error.
  333. //
  334. // func doSomething(..) (err error) {
  335. // f := acquireResource()
  336. // defer func() {
  337. // err = multierr.Append(err, f.Close())
  338. // }()
  339. func Append(left error, right error) error {
  340. switch {
  341. case left == nil:
  342. return right
  343. case right == nil:
  344. return left
  345. }
  346. if _, ok := right.(*multiError); !ok {
  347. if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
  348. // Common case where the error on the left is constantly being
  349. // appended to.
  350. errs := append(l.errors, right)
  351. return &multiError{errors: errs}
  352. } else if !ok {
  353. // Both errors are single errors.
  354. return &multiError{errors: []error{left, right}}
  355. }
  356. }
  357. // Either right or both, left and right, are multiErrors. Rely on usual
  358. // expensive logic.
  359. errors := [2]error{left, right}
  360. return fromSlice(errors[0:])
  361. }