Documentation
¶
Overview ¶
package errutil contains some simple error helpers
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Defer ¶
Defer is for use when defering a function call that can return an error. If the referenced error is nil but the callback returns a non-nil error, it sets the reference to the value of the returned error.
Example ¶
Calling Close() on an io.WriteCloser can return an important error encountered while flushing to disk. Don't risk missing them by using a plain defer w.Close(). Use errutil.Defer to capture the return value.
package main
import (
"fmt"
"github.com/carlmjohnson/errutil"
)
type closer struct{}
func (c closer) Close() error {
return fmt.Errorf("<had problem closing!>")
}
func openThingie() (c closer, err error) { return }
// Calling Close() on an io.WriteCloser can return an important error
// encountered while flushing to disk. Don't risk missing them by
// using a plain defer w.Close(). Use errutil.Defer to capture the return value.
func main() {
// If you just defer a close call, you can miss an error
return1 := func() error {
thing, err := openThingie()
if err != nil {
return err
}
defer thing.Close() // oh no, this returned an error!
// do stuff...
return nil
}()
fmt.Println(return1) // == <nil>
// Use errutil.Defer and a named return to capture the error
return2 := func() (err error) {
thing, err := openThingie()
if err != nil {
return err
}
defer errutil.Defer(&err, thing.Close)
// do stuff...
return nil
}()
fmt.Println(return2) // == <had problem closing!>
}
Output: <nil> <had problem closing!>
func ExecParallel ¶ added in v0.20.1
ExecParallel runs the functions in separate goroutines and then merges the returned errors, if any. Any panics in goroutines will be caught and converted into errors.
Example ¶
package main
import (
"errors"
"fmt"
"time"
"github.com/carlmjohnson/errutil"
)
func main() {
start := time.Now()
err := errutil.ExecParallel(func() error {
time.Sleep(1 * time.Second)
return nil
}, func() error {
time.Sleep(1 * time.Second)
return errors.New("one error")
}, func() error {
time.Sleep(1 * time.Second)
panic("ahhh")
})
fmt.Println("ran parallel?", time.Since(start) < 2*time.Second)
for i, suberr := range errutil.AsSlice(err) {
fmt.Printf("error %d: %v\n", i+1, suberr)
}
}
Output: ran parallel? true error 1: one error error 2: panic: ahhh
func Merge ¶
Merge is a convenience method for making a Slice of errors and calling the Merge method.
Example ¶
package main
import (
"fmt"
"github.com/carlmjohnson/errutil"
)
func main() {
// A function that sometimes returns an error
called := 0
someFunc := func() error {
called++
if called%2 == 0 {
return fmt.Errorf("even error: %d!", called)
}
return nil
}
// We do a series of operations that might return an error.
err := someFunc()
// This time, it didn't return an error.
fmt.Printf("%+v\n", err)
// After each operation, we merge it into our existing error variable
// then do the next operation.
err = errutil.Merge(err, someFunc())
err = errutil.Merge(err, someFunc())
err = errutil.Merge(err, someFunc())
// Finally, we can return the result
fmt.Printf("%+v", err)
// Or loop through results
for i, suberr := range errutil.AsSlice(err) {
fmt.Printf("suberr[%d]: %v\n", i, suberr)
}
}
Output: <nil> 2 errors: error 1: even error: 2! error 2: even error: 4! suberr[0]: even error: 2! suberr[1]: even error: 4!
func Prefix ¶ added in v0.21.1
Prefix will prefix an error with a fixed string if it is non-nil.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/carlmjohnson/errutil"
)
func main() {
maybeErr1 := func(ok bool) (err error) {
defer errutil.Prefix(&err, "maybeErr1")
if !ok {
return errors.New("oh no!")
}
return nil
}
maybeErr2 := func(x, y int) (err error) {
defer errutil.Prefix(&err, "maybeErr2(%d, %d)", x, y)
if x+y > 1 {
return errors.New("uh oh!")
}
return nil
}
fmt.Println(maybeErr1(true))
fmt.Println(maybeErr1(false))
fmt.Println(maybeErr2(1, -1))
fmt.Println(maybeErr2(1, 1))
}
Output: <nil> maybeErr1: oh no! <nil> maybeErr2(1, 1): uh oh!
func Recover ¶ added in v0.21.5
func Recover(errp *error)
Recover catches any panics and converts them to errors when deferred.
Example ¶
package main
import (
"fmt"
"github.com/carlmjohnson/errutil"
)
func main() {
maybePanic := func(throws bool) (err error) {
defer errutil.Recover(&err)
if throws {
panic("ahhh!")
}
return nil
}
err := maybePanic(false)
fmt.Printf("error 1: %v\n", err)
err = maybePanic(true)
fmt.Printf("error 2: %v\n", err)
}
Output: error 1: <nil> error 2: panic: ahhh!
func Trace ¶ added in v0.21.4
func Trace(errp *error)
Trace prefixes an error with caller information if the error is not nil.
Example ¶
package main
import (
"errors"
"fmt"
"github.com/carlmjohnson/errutil"
)
func traceErr1(ok bool) (err error) {
defer errutil.Trace(&err)
if !ok {
return errors.New("oh no!")
}
return nil
}
func traceErr2(x, y int) (err error) {
defer errutil.Trace(&err)
if x+y > 1 {
return errors.New("uh oh!")
}
return nil
}
func main() {
fmt.Println(traceErr1(true))
fmt.Println(traceErr1(false))
fmt.Println(traceErr2(1, -1))
fmt.Println(traceErr2(1, 1))
}
Output: <nil> problem in github.com/carlmjohnson/errutil_test.traceErr1 (prefix_example_test.go:13): oh no! <nil> problem in github.com/carlmjohnson/errutil_test.traceErr2 (prefix_example_test.go:21): uh oh!
Types ¶
type Multierr ¶
Multierr is an interface allowing external types containing multiple errors (such as uber-go/multierr) to be treated as a Slice.
type Slice ¶
type Slice []error
Slice is a slice of errors. Use it to collect possible errors then create a Multierr with the Merge method.
Example ¶
package main
import (
"fmt"
"github.com/carlmjohnson/errutil"
)
func main() {
// A function that sometimes returns an error
called := 0
someFunc := func() error {
called++
if called%2 == 0 {
return fmt.Errorf("even error!")
}
return nil
}
// The empty value can be used
var errs errutil.Slice
// Do something that returns an error sometimes
err := someFunc()
errs.Push(err)
// Now merging them to produces <nil> error
fmt.Println(errs.Merge())
// But if we add non-nil errors...
err = someFunc()
errs.Push(err)
errs.Push(err)
// Merge returns non-nil
fmt.Println(errs.Merge())
}
Output: <nil> 2 errors: even error!; even error!
Example (ExtendedFormat) ¶
package main
import (
"fmt"
"github.com/carlmjohnson/errutil"
)
func main() {
var errs errutil.Slice
// Collect several errors
err := fmt.Errorf("error 1")
errs.Push(err)
err = fmt.Errorf("error 2")
errs.Push(err)
// ...and a nil error
err = nil
errs.Push(err)
// ...then a real error again
err = fmt.Errorf("error 3")
errs.Push(err)
// Now merge and output them in extended format
fmt.Printf("%+v", errs.Merge())
}
Output: 3 errors: error 1: error 1 error 2: error 2 error 3: error 3
func AsSlice ¶ added in v0.21.2
AsSlice converts err into Slice. If err is nil, the slice has length 0. If the err is a Multierr, it returns the underlying Slice. All other errors become a slice of length 1.
AsSlice also understands how to unwrap hashicorp/go-multierror.