You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

error.go 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. // Copyright (c) 2017-2021 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.Append(reader.Close(), writer.Close())
  36. //
  37. // The underlying list of errors for a returned error object may be retrieved
  38. // with the Errors function.
  39. //
  40. // errors := multierr.Errors(err)
  41. // if len(errors) > 0 {
  42. // fmt.Println("The following errors occurred:", errors)
  43. // }
  44. //
  45. // Appending from a loop
  46. //
  47. // You sometimes need to append into an error from a loop.
  48. //
  49. // var err error
  50. // for _, item := range items {
  51. // err = multierr.Append(err, process(item))
  52. // }
  53. //
  54. // Cases like this may require knowledge of whether an individual instance
  55. // failed. This usually requires introduction of a new variable.
  56. //
  57. // var err error
  58. // for _, item := range items {
  59. // if perr := process(item); perr != nil {
  60. // log.Warn("skipping item", item)
  61. // err = multierr.Append(err, perr)
  62. // }
  63. // }
  64. //
  65. // multierr includes AppendInto to simplify cases like this.
  66. //
  67. // var err error
  68. // for _, item := range items {
  69. // if multierr.AppendInto(&err, process(item)) {
  70. // log.Warn("skipping item", item)
  71. // }
  72. // }
  73. //
  74. // This will append the error into the err variable, and return true if that
  75. // individual error was non-nil.
  76. //
  77. // See AppendInto for more information.
  78. //
  79. // Deferred Functions
  80. //
  81. // Go makes it possible to modify the return value of a function in a defer
  82. // block if the function was using named returns. This makes it possible to
  83. // record resource cleanup failures from deferred blocks.
  84. //
  85. // func sendRequest(req Request) (err error) {
  86. // conn, err := openConnection()
  87. // if err != nil {
  88. // return err
  89. // }
  90. // defer func() {
  91. // err = multierr.Append(err, conn.Close())
  92. // }()
  93. // // ...
  94. // }
  95. //
  96. // multierr provides the Invoker type and AppendInvoke function to make cases
  97. // like the above simpler and obviate the need for a closure. The following is
  98. // roughly equivalent to the example above.
  99. //
  100. // func sendRequest(req Request) (err error) {
  101. // conn, err := openConnection()
  102. // if err != nil {
  103. // return err
  104. // }
  105. // defer multierr.AppendInvoke(err, multierr.Close(conn))
  106. // // ...
  107. // }
  108. //
  109. // See AppendInvoke and Invoker for more information.
  110. //
  111. // Advanced Usage
  112. //
  113. // Errors returned by Combine and Append MAY implement the following
  114. // interface.
  115. //
  116. // type errorGroup interface {
  117. // // Returns a slice containing the underlying list of errors.
  118. // //
  119. // // This slice MUST NOT be modified by the caller.
  120. // Errors() []error
  121. // }
  122. //
  123. // Note that if you need access to list of errors behind a multierr error, you
  124. // should prefer using the Errors function. That said, if you need cheap
  125. // read-only access to the underlying errors slice, you can attempt to cast
  126. // the error to this interface. You MUST handle the failure case gracefully
  127. // because errors returned by Combine and Append are not guaranteed to
  128. // implement this interface.
  129. //
  130. // var errors []error
  131. // group, ok := err.(errorGroup)
  132. // if ok {
  133. // errors = group.Errors()
  134. // } else {
  135. // errors = []error{err}
  136. // }
  137. package multierr // import "go.uber.org/multierr"
  138. import (
  139. "bytes"
  140. "errors"
  141. "fmt"
  142. "io"
  143. "strings"
  144. "sync"
  145. "go.uber.org/atomic"
  146. )
  147. var (
  148. // Separator for single-line error messages.
  149. _singlelineSeparator = []byte("; ")
  150. // Prefix for multi-line messages
  151. _multilinePrefix = []byte("the following errors occurred:")
  152. // Prefix for the first and following lines of an item in a list of
  153. // multi-line error messages.
  154. //
  155. // For example, if a single item is:
  156. //
  157. // foo
  158. // bar
  159. //
  160. // It will become,
  161. //
  162. // - foo
  163. // bar
  164. _multilineSeparator = []byte("\n - ")
  165. _multilineIndent = []byte(" ")
  166. )
  167. // _bufferPool is a pool of bytes.Buffers.
  168. var _bufferPool = sync.Pool{
  169. New: func() interface{} {
  170. return &bytes.Buffer{}
  171. },
  172. }
  173. type errorGroup interface {
  174. Errors() []error
  175. }
  176. // Errors returns a slice containing zero or more errors that the supplied
  177. // error is composed of. If the error is nil, a nil slice is returned.
  178. //
  179. // err := multierr.Append(r.Close(), w.Close())
  180. // errors := multierr.Errors(err)
  181. //
  182. // If the error is not composed of other errors, the returned slice contains
  183. // just the error that was passed in.
  184. //
  185. // Callers of this function are free to modify the returned slice.
  186. func Errors(err error) []error {
  187. if err == nil {
  188. return nil
  189. }
  190. // Note that we're casting to multiError, not errorGroup. Our contract is
  191. // that returned errors MAY implement errorGroup. Errors, however, only
  192. // has special behavior for multierr-specific error objects.
  193. //
  194. // This behavior can be expanded in the future but I think it's prudent to
  195. // start with as little as possible in terms of contract and possibility
  196. // of misuse.
  197. eg, ok := err.(*multiError)
  198. if !ok {
  199. return []error{err}
  200. }
  201. errors := eg.Errors()
  202. result := make([]error, len(errors))
  203. copy(result, errors)
  204. return result
  205. }
  206. // multiError is an error that holds one or more errors.
  207. //
  208. // An instance of this is guaranteed to be non-empty and flattened. That is,
  209. // none of the errors inside multiError are other multiErrors.
  210. //
  211. // multiError formats to a semi-colon delimited list of error messages with
  212. // %v and with a more readable multi-line format with %+v.
  213. type multiError struct {
  214. copyNeeded atomic.Bool
  215. errors []error
  216. }
  217. var _ errorGroup = (*multiError)(nil)
  218. // Errors returns the list of underlying errors.
  219. //
  220. // This slice MUST NOT be modified.
  221. func (merr *multiError) Errors() []error {
  222. if merr == nil {
  223. return nil
  224. }
  225. return merr.errors
  226. }
  227. // As attempts to find the first error in the error list that matches the type
  228. // of the value that target points to.
  229. //
  230. // This function allows errors.As to traverse the values stored on the
  231. // multierr error.
  232. func (merr *multiError) As(target interface{}) bool {
  233. for _, err := range merr.Errors() {
  234. if errors.As(err, target) {
  235. return true
  236. }
  237. }
  238. return false
  239. }
  240. // Is attempts to match the provided error against errors in the error list.
  241. //
  242. // This function allows errors.Is to traverse the values stored on the
  243. // multierr error.
  244. func (merr *multiError) Is(target error) bool {
  245. for _, err := range merr.Errors() {
  246. if errors.Is(err, target) {
  247. return true
  248. }
  249. }
  250. return false
  251. }
  252. func (merr *multiError) Error() string {
  253. if merr == nil {
  254. return ""
  255. }
  256. buff := _bufferPool.Get().(*bytes.Buffer)
  257. buff.Reset()
  258. merr.writeSingleline(buff)
  259. result := buff.String()
  260. _bufferPool.Put(buff)
  261. return result
  262. }
  263. func (merr *multiError) Format(f fmt.State, c rune) {
  264. if c == 'v' && f.Flag('+') {
  265. merr.writeMultiline(f)
  266. } else {
  267. merr.writeSingleline(f)
  268. }
  269. }
  270. func (merr *multiError) writeSingleline(w io.Writer) {
  271. first := true
  272. for _, item := range merr.errors {
  273. if first {
  274. first = false
  275. } else {
  276. w.Write(_singlelineSeparator)
  277. }
  278. io.WriteString(w, item.Error())
  279. }
  280. }
  281. func (merr *multiError) writeMultiline(w io.Writer) {
  282. w.Write(_multilinePrefix)
  283. for _, item := range merr.errors {
  284. w.Write(_multilineSeparator)
  285. writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
  286. }
  287. }
  288. // Writes s to the writer with the given prefix added before each line after
  289. // the first.
  290. func writePrefixLine(w io.Writer, prefix []byte, s string) {
  291. first := true
  292. for len(s) > 0 {
  293. if first {
  294. first = false
  295. } else {
  296. w.Write(prefix)
  297. }
  298. idx := strings.IndexByte(s, '\n')
  299. if idx < 0 {
  300. idx = len(s) - 1
  301. }
  302. io.WriteString(w, s[:idx+1])
  303. s = s[idx+1:]
  304. }
  305. }
  306. type inspectResult struct {
  307. // Number of top-level non-nil errors
  308. Count int
  309. // Total number of errors including multiErrors
  310. Capacity int
  311. // Index of the first non-nil error in the list. Value is meaningless if
  312. // Count is zero.
  313. FirstErrorIdx int
  314. // Whether the list contains at least one multiError
  315. ContainsMultiError bool
  316. }
  317. // Inspects the given slice of errors so that we can efficiently allocate
  318. // space for it.
  319. func inspect(errors []error) (res inspectResult) {
  320. first := true
  321. for i, err := range errors {
  322. if err == nil {
  323. continue
  324. }
  325. res.Count++
  326. if first {
  327. first = false
  328. res.FirstErrorIdx = i
  329. }
  330. if merr, ok := err.(*multiError); ok {
  331. res.Capacity += len(merr.errors)
  332. res.ContainsMultiError = true
  333. } else {
  334. res.Capacity++
  335. }
  336. }
  337. return
  338. }
  339. // fromSlice converts the given list of errors into a single error.
  340. func fromSlice(errors []error) error {
  341. res := inspect(errors)
  342. switch res.Count {
  343. case 0:
  344. return nil
  345. case 1:
  346. // only one non-nil entry
  347. return errors[res.FirstErrorIdx]
  348. case len(errors):
  349. if !res.ContainsMultiError {
  350. // already flat
  351. return &multiError{errors: errors}
  352. }
  353. }
  354. nonNilErrs := make([]error, 0, res.Capacity)
  355. for _, err := range errors[res.FirstErrorIdx:] {
  356. if err == nil {
  357. continue
  358. }
  359. if nested, ok := err.(*multiError); ok {
  360. nonNilErrs = append(nonNilErrs, nested.errors...)
  361. } else {
  362. nonNilErrs = append(nonNilErrs, err)
  363. }
  364. }
  365. return &multiError{errors: nonNilErrs}
  366. }
  367. // Combine combines the passed errors into a single error.
  368. //
  369. // If zero arguments were passed or if all items are nil, a nil error is
  370. // returned.
  371. //
  372. // Combine(nil, nil) // == nil
  373. //
  374. // If only a single error was passed, it is returned as-is.
  375. //
  376. // Combine(err) // == err
  377. //
  378. // Combine skips over nil arguments so this function may be used to combine
  379. // together errors from operations that fail independently of each other.
  380. //
  381. // multierr.Combine(
  382. // reader.Close(),
  383. // writer.Close(),
  384. // pipe.Close(),
  385. // )
  386. //
  387. // If any of the passed errors is a multierr error, it will be flattened along
  388. // with the other errors.
  389. //
  390. // multierr.Combine(multierr.Combine(err1, err2), err3)
  391. // // is the same as
  392. // multierr.Combine(err1, err2, err3)
  393. //
  394. // The returned error formats into a readable multi-line error message if
  395. // formatted with %+v.
  396. //
  397. // fmt.Sprintf("%+v", multierr.Combine(err1, err2))
  398. func Combine(errors ...error) error {
  399. return fromSlice(errors)
  400. }
  401. // Append appends the given errors together. Either value may be nil.
  402. //
  403. // This function is a specialization of Combine for the common case where
  404. // there are only two errors.
  405. //
  406. // err = multierr.Append(reader.Close(), writer.Close())
  407. //
  408. // The following pattern may also be used to record failure of deferred
  409. // operations without losing information about the original error.
  410. //
  411. // func doSomething(..) (err error) {
  412. // f := acquireResource()
  413. // defer func() {
  414. // err = multierr.Append(err, f.Close())
  415. // }()
  416. func Append(left error, right error) error {
  417. switch {
  418. case left == nil:
  419. return right
  420. case right == nil:
  421. return left
  422. }
  423. if _, ok := right.(*multiError); !ok {
  424. if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
  425. // Common case where the error on the left is constantly being
  426. // appended to.
  427. errs := append(l.errors, right)
  428. return &multiError{errors: errs}
  429. } else if !ok {
  430. // Both errors are single errors.
  431. return &multiError{errors: []error{left, right}}
  432. }
  433. }
  434. // Either right or both, left and right, are multiErrors. Rely on usual
  435. // expensive logic.
  436. errors := [2]error{left, right}
  437. return fromSlice(errors[0:])
  438. }
  439. // AppendInto appends an error into the destination of an error pointer and
  440. // returns whether the error being appended was non-nil.
  441. //
  442. // var err error
  443. // multierr.AppendInto(&err, r.Close())
  444. // multierr.AppendInto(&err, w.Close())
  445. //
  446. // The above is equivalent to,
  447. //
  448. // err := multierr.Append(r.Close(), w.Close())
  449. //
  450. // As AppendInto reports whether the provided error was non-nil, it may be
  451. // used to build a multierr error in a loop more ergonomically. For example:
  452. //
  453. // var err error
  454. // for line := range lines {
  455. // var item Item
  456. // if multierr.AppendInto(&err, parse(line, &item)) {
  457. // continue
  458. // }
  459. // items = append(items, item)
  460. // }
  461. //
  462. // Compare this with a version that relies solely on Append:
  463. //
  464. // var err error
  465. // for line := range lines {
  466. // var item Item
  467. // if parseErr := parse(line, &item); parseErr != nil {
  468. // err = multierr.Append(err, parseErr)
  469. // continue
  470. // }
  471. // items = append(items, item)
  472. // }
  473. func AppendInto(into *error, err error) (errored bool) {
  474. if into == nil {
  475. // We panic if 'into' is nil. This is not documented above
  476. // because suggesting that the pointer must be non-nil may
  477. // confuse users into thinking that the error that it points
  478. // to must be non-nil.
  479. panic("misuse of multierr.AppendInto: into pointer must not be nil")
  480. }
  481. if err == nil {
  482. return false
  483. }
  484. *into = Append(*into, err)
  485. return true
  486. }
  487. // Invoker is an operation that may fail with an error. Use it with
  488. // AppendInvoke to append the result of calling the function into an error.
  489. // This allows you to conveniently defer capture of failing operations.
  490. //
  491. // See also, Close and Invoke.
  492. type Invoker interface {
  493. Invoke() error
  494. }
  495. // Invoke wraps a function which may fail with an error to match the Invoker
  496. // interface. Use it to supply functions matching this signature to
  497. // AppendInvoke.
  498. //
  499. // For example,
  500. //
  501. // func processReader(r io.Reader) (err error) {
  502. // scanner := bufio.NewScanner(r)
  503. // defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
  504. // for scanner.Scan() {
  505. // // ...
  506. // }
  507. // // ...
  508. // }
  509. //
  510. // In this example, the following line will construct the Invoker right away,
  511. // but defer the invocation of scanner.Err() until the function returns.
  512. //
  513. // defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
  514. type Invoke func() error
  515. // Invoke calls the supplied function and returns its result.
  516. func (i Invoke) Invoke() error { return i() }
  517. // Close builds an Invoker that closes the provided io.Closer. Use it with
  518. // AppendInvoke to close io.Closers and append their results into an error.
  519. //
  520. // For example,
  521. //
  522. // func processFile(path string) (err error) {
  523. // f, err := os.Open(path)
  524. // if err != nil {
  525. // return err
  526. // }
  527. // defer multierr.AppendInvoke(&err, multierr.Close(f))
  528. // return processReader(f)
  529. // }
  530. //
  531. // In this example, multierr.Close will construct the Invoker right away, but
  532. // defer the invocation of f.Close until the function returns.
  533. //
  534. // defer multierr.AppendInvoke(&err, multierr.Close(f))
  535. func Close(closer io.Closer) Invoker {
  536. return Invoke(closer.Close)
  537. }
  538. // AppendInvoke appends the result of calling the given Invoker into the
  539. // provided error pointer. Use it with named returns to safely defer
  540. // invocation of fallible operations until a function returns, and capture the
  541. // resulting errors.
  542. //
  543. // func doSomething(...) (err error) {
  544. // // ...
  545. // f, err := openFile(..)
  546. // if err != nil {
  547. // return err
  548. // }
  549. //
  550. // // multierr will call f.Close() when this function returns and
  551. // // if the operation fails, its append its error into the
  552. // // returned error.
  553. // defer multierr.AppendInvoke(&err, multierr.Close(f))
  554. //
  555. // scanner := bufio.NewScanner(f)
  556. // // Similarly, this scheduled scanner.Err to be called and
  557. // // inspected when the function returns and append its error
  558. // // into the returned error.
  559. // defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
  560. //
  561. // // ...
  562. // }
  563. //
  564. // Without defer, AppendInvoke behaves exactly like AppendInto.
  565. //
  566. // err := // ...
  567. // multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
  568. //
  569. // // ...is roughly equivalent to...
  570. //
  571. // err := // ...
  572. // multierr.AppendInto(&err, foo())
  573. //
  574. // The advantage of the indirection introduced by Invoker is to make it easy
  575. // to defer the invocation of a function. Without this indirection, the
  576. // invoked function will be evaluated at the time of the defer block rather
  577. // than when the function returns.
  578. //
  579. // // BAD: This is likely not what the caller intended. This will evaluate
  580. // // foo() right away and append its result into the error when the
  581. // // function returns.
  582. // defer multierr.AppendInto(&err, foo())
  583. //
  584. // // GOOD: This will defer invocation of foo unutil the function returns.
  585. // defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
  586. //
  587. // multierr provides a few Invoker implementations out of the box for
  588. // convenience. See Invoker for more information.
  589. func AppendInvoke(into *error, invoker Invoker) {
  590. AppendInto(into, invoker.Invoke())
  591. }