Documentation ¶
Overview ¶
Package err2 provides three main functionality:
- err2 package includes helper functions for error handling & automatic stack tracing
- try package is for error checking
- assert package is for design-by-contract and preconditions both for normal runtime and for testing
The traditional error handling idiom in Go is roughly akin to
if err != nil { return err }
which applied recursively.
The err2 package drives programmers to focus more on error handling rather than checking errors. We think that checks should be so easy that we never forget them. The CopyFile example shows how it works:
// CopyFile copies source file to the given destination. If any error occurs it // returns error value describing the reason. func CopyFile(src, dst string) (err error) { // Add first error handler just to annotate the error properly. defer err2.Returnf(&err, "copy %s %s", src, dst) // Try to open the file. If error occurs now, err will be annotated and // returned properly thanks to above err2.Returnf. r := try.To1(os.Open(src)) defer r.Close() // Try to create a file. If error occurs now, err will be annotated and // returned properly. w := try.To1(os.Create(dst)) // Add error handler to clean up the destination file. Place it here that // the next deferred close is called before our Remove call. defer err2.Handle(&err, func() { os.Remove(dst) }) defer w.Close() // Try to copy the file. If error occurs now, all previous error handlers // will be called in the reversed order. And final return error is // properly annotated in all the cases. try.To1(io.Copy(w, r)) // All OK, just return nil. return nil }
Error checks and Automatic Error Propagation ¶
The try package provides convenient helpers to check the errors. For example, instead of
b, err := ioutil.ReadAll(r) if err != nil { return err }
we can write
b := try.To1(ioutil.ReadAll(r))
Note that try.ToX functions are as fast as if err != nil statements. Please see the try package documentation for more information about the error checks.
Automatic Stack Tracing ¶
err2 offers optional stack tracing. And yes, it's fully automatic. Just set the tracers to the stream you want traces to be written:
err2.SetErrorTracer(os.Stderr) // write error stack trace to stderr or err2.SetPanicTracer(log.Writer()) // panic stack trace to std logger
Error handling ¶
Package err2 relies on declarative control structures to achieve error and panic safety. In every function which uses err2 or try package for error-checking has to have at least one declarative error handler if it returns error value. If there are no error handlers and error occurs it panics. We think that panicking for the errors is much better than not checking errors at all. Nevertheless, if the call stack includes any err2 error handlers like err2.Handle the error is handled where the handler is saved to defer-stack. (defer is not lexically scoped)
err2 includes many examples to play with like previous CopyFile. Please see them for more information.
Example ¶
package main import ( "fmt" "io" "os" "github.com/lainio/err2" "github.com/lainio/err2/try" ) func CopyFile(src, dst string) (err error) { defer err2.Returnf(&err, "copy file %s->%s", src, dst) // These try.To() checkers are as fast as `if err != nil {}` r := try.To1(os.Open(src)) defer r.Close() w := try.To1(os.Create(dst)) defer err2.Handle(&err, func() { os.Remove(dst) }) defer w.Close() try.To1(io.Copy(w, r)) return nil } func main() { // To see how automatic stack tracing works please run this example with: // go test -v -run='^Example$' err2.SetErrorTracer(os.Stderr) err := CopyFile("/notfound/path/file.go", "/notfound/path/file.bak") if err != nil { fmt.Println(err) } }
Output: copy file /notfound/path/file.go->/notfound/path/file.bak: open /notfound/path/file.go: no such file or directory
Index ¶
- Variables
- func Catch(f func(err error))
- func CatchAll(errorHandler func(err error), panicHandler func(v any))
- func CatchTrace(errorHandler func(err error))
- func ErrorTracer() io.Writer
- func Handle(err *error, handlerFn func())
- func PanicTracer() io.Writer
- func Return(err *error)
- func Returnf(err *error, format string, args ...any)
- func Returnw(err *error, format string, args ...any)
- func SetErrorTracer(w io.Writer)
- func SetPanicTracer(w io.Writer)
- func SetTracers(w io.Writer)
- func Throwf(format string, args ...any)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // NotFound is similar *no-error* like io.EOF for those who really want to // use error return values to transport non errors. It's far better to have // discriminated unions as errors for function calls. But if you insist the // related helpers are in they try package: try.IsNotFound(), ... These // 'global' errors and their helper functions in try package are for // experimenting now. NotFound = errors.New("not found") NotExist = errors.New("not exist") Exist = errors.New("already exist") NotAccess = errors.New("permission denied") )
Functions ¶
func Catch ¶
func Catch(f func(err error))
Catch is a convenient helper to those functions that doesn't return errors. There can be only one deferred Catch function per non error returning function like main(). It doesn't catch panics and runtime errors. If that's important use CatchAll or CatchTrace instead. See Handle for more information.
func CatchAll ¶
CatchAll is a helper function to catch and write handlers for all errors and all panics thrown in the current go routine. It and CatchTrace are preferred helpers for go workers on long running servers, because they stop panics as well.
Note, if any Tracer is set stack traces are printed automatically. If you want to do it in the handlers by yourself, auto tracers should be nil.
func CatchTrace ¶
func CatchTrace(errorHandler func(err error))
CatchTrace is a helper function to catch and handle all errors. It also recovers a panic and prints its call stack. CatchTrace and CatchAll are preferred helpers for go-workers on long-running servers because they stop panics as well.
CatchTrace prints only panic and runtime.Error stack trace if ErrorTracer isn't set. If it's set it prints both. The panic trace is printed to stderr. If you need panic trace to be printed to some other io.Writer than os.Stderr, you should use CatchAll or Catch with tracers.
func ErrorTracer ¶ added in v0.8.9
ErrorTracer returns current io.Writer for automatic error stack tracing.
func Handle ¶
func Handle(err *error, handlerFn func())
Handle is for adding an error handler to a function by deferring. It's for functions returning errors themself. For those functions that don't return errors, there is a CatchXxxx functions. The handler is called only when err != nil. There is no limit how many Handle functions can be added to defer stack. They all are called if an error has occurred and they are in deferred.
Example ¶
package main import ( "fmt" "github.com/lainio/err2" "github.com/lainio/err2/try" ) func throw() (string, error) { return "", fmt.Errorf("this is an ERROR") } func main() { doSomething := func(a, b int) (err error) { defer err2.Handle(&err, func() { // Example for just annotating current err. Normally Handle is // used for cleanup. See CopyFile example for more information. // Use err2.Returnf for err annotation. err = fmt.Errorf("error with (%d, %d): %v", a, b, err) }) try.To1(throw()) return err } err := doSomething(1, 2) fmt.Printf("%v", err) }
Output: error with (1, 2): this is an ERROR
func PanicTracer ¶ added in v0.8.9
PanicTracer returns current io.Writer for automatic panic stack tracing. Note that runtime.Error types which are transported by panics are controlled by this.
func Return ¶
func Return(err *error)
Return is the same as Handle but it's for functions that don't wrap or annotate their errors. It's still needed to break panicking which is used for error transport in err2. If you want to annotate errors see Returnf and Returnw functions for more information.
Example ¶
package main import ( "github.com/lainio/err2" "github.com/lainio/err2/try" ) func noThrow() (string, error) { return "test", nil } func main() { var err error defer err2.Return(&err) try.To1(noThrow()) }
Output:
func Returnf ¶
Returnf builds an error. It's similar to fmt.Errorf, but it's called only if error != nil. It uses '%v' to wrap the error not '%w'. Use Returnw for that.
Example ¶
package main import ( "fmt" "github.com/lainio/err2" "github.com/lainio/err2/try" ) func throw() (string, error) { return "", fmt.Errorf("this is an ERROR") } func main() { annotated := func() (err error) { defer err2.Returnf(&err, "annotated: %s", "err2") try.To1(throw()) return err } err := annotated() fmt.Printf("%v", err) }
Output: annotated: err2: this is an ERROR
Example (DeferStack) ¶
package main import ( "fmt" "github.com/lainio/err2" "github.com/lainio/err2/try" ) func throw() (string, error) { return "", fmt.Errorf("this is an ERROR") } func main() { annotated := func() (err error) { defer err2.Returnf(&err, "annotated 2nd") defer err2.Returnf(&err, "annotated 1st") try.To1(throw()) return err } err := annotated() fmt.Printf("%v", err) }
Output: annotated 2nd: annotated 1st: this is an ERROR
Example (Empty) ¶
package main import ( "fmt" "github.com/lainio/err2" "github.com/lainio/err2/try" ) func throw() (string, error) { return "", fmt.Errorf("this is an ERROR") } func main() { annotated := func() (err error) { defer err2.Returnf(&err, "annotated") try.To1(throw()) return err } err := annotated() fmt.Printf("%v", err) }
Output: annotated: this is an ERROR
func Returnw ¶ added in v0.8.0
Returnw wraps an error with '%w'. It's similar to fmt.Errorf, but it's called only if error != nil. If you don't want to wrap the error use Returnf instead.
func SetErrorTracer ¶ added in v0.8.9
SetErrorTracer sets a io.Writer for automatic error stack tracing. Note that runtime.Error types which are transported by panics are controlled by this.
func SetPanicTracer ¶ added in v0.8.9
SetPanicTracer sets a io.Writer for automatic panic stack tracing. Note that runtime.Error types which are transported by panics are controlled by this.
func SetTracers ¶ added in v0.8.9
SetTracers a convenient helper to set a io.Writer for error and panic stack tracing.
func Throwf ¶ added in v0.8.7
Throwf builds and throws (panics) an error. For creation it's similar to fmt.Errorf. Because panic is used to transport the error instead of error return value, it's called only if you want to non-local control structure for error handling, i.e. your current function doesn't have error return value. NOTE, Throwf is rarely needed. We suggest to use error return values instead. Throwf is offered for deep recursive algorithms to help readability.
func yourFn() (res any) { ... if badHappens { err2.Throwf("we cannot do that for %v", subject) } ... }
Example ¶
package main import ( "fmt" "github.com/lainio/err2" ) func main() { type fn func(v int) int var recursion fn const recursionLimit = 77 // 12+11+10+9+8+7+6+5+4+3+2+1 = 78 recursion = func(i int) int { if i > recursionLimit { // simulated error case err2.Throwf("helper failed at: %d", i) } else if i == 0 { return 0 // recursion without error ends here } return i + recursion(i-1) } annotated := func() (err error) { defer err2.Returnf(&err, "annotated: %s", "err2") r := recursion(12) // call recursive algorithm successfully recursion(r) // call recursive algorithm unsuccessfully return err } err := annotated() fmt.Printf("%v", err) }
Output: annotated: err2: helper failed at: 78
Types ¶
This section is empty.
Directories ¶
Path | Synopsis |
---|---|
Package assert includes runtime assertion helpers both for normal execution as well as a assertion package for Go's testing.
|
Package assert includes runtime assertion helpers both for normal execution as well as a assertion package for Go's testing. |
internal
|
|
handler
Package handler implements handler for objects returned recovery() function.
|
Package handler implements handler for objects returned recovery() function. |
tracer
Package tracer implements thread safe storage for stace trace writers.
|
Package tracer implements thread safe storage for stace trace writers. |
Package main includes samples of err2.
|
Package main includes samples of err2. |
Package try is a package for try.ToX functions that implement the error checking.
|
Package try is a package for try.ToX functions that implement the error checking. |