This Go package provides tools for compact error and panic handling. Instead of the traditional:
x, err := f()
if err != nil {
return fmt.Sprintf("annotate: %w", err)
}You can write:
x, err := f()
try.Checkw(err, "annotate")The functions Check* are used for checking and handling errors.
For example, instead of
b, err := ioutil.ReadAll(r)
if err != nil {
return err
}
...we can call
b, err := ioutil.ReadAll(r)
try.Check(err)These function do require a deferred error handler at the top of the function.
Every function which uses try for error-checking should have at least one deferred
try.Handle* function. try propagates errors via a panic, and these functions recover the error. If this is ommitted, an error will panic up the stack until there is a recover.
func do(x int) (err error) {
defer try.Handlew(&err, "do %d", x)
...
}There is also
Handlew: annotate the error with a message and wrap it (like fmt.Errorf with %w)Handlef: annotate the error with a message and wrap it (like fmt.Errorf with %v)Handle: call a function with the errorHandleCleanup: call a cleanup function
There are also helpers Catch*, and ErrorFromRecovery that are useful for catching errors and panics in functions that do not return errors. These are generally callbacks, goroutines, and main.
The handler functions will also annotate panics and then rethrow them. This unifies error and panic handling. This can sometimes make the difference between a panic being hard to debug to being easy.
This is a fork of github.com/lainio/err2 with a different user facing API. Internally the panic/recovery mechanism of propagating errors is the same. Besides only returning errors and not passing through values, differences are:
- Tracing is handled differently.
- There is no automatic mechanism for printing panics, instead users should create their own standard way of doing this. The original stack trace printing code is still available under the stackprint module.
- Errors themselves are wrapped up with a stack trace that can be recovered and printed with "%+v".
- Panics are annotated by the
Handle*functions
There are scripts under the ./codemod directory (upgrade.sh and downgrade.sh) to automatically translate code to use try or to downgrade it back to the original error handling.
The original err2 implements similar error handling mechanism as drafted in the original
check/handle
proposal.
try encourages the single use of a defer statement at the top of the function and then using the try.Try functions to explicitly declare the error handlers for a function, similar to this new proposal.
The package accomplishes error handling internally by using panic/recovery, which is less than ideal.
However, it works out well because:
- benchmarks show that when there is no error the overhead is non-existant
- it helps with properly handling panics
In general code should not pass errors in performance sensitive paths. Normally if it does (for example APIs that use EOF as an error), the API is not well designed.
The mandatory use of the defer might prevent some code optimisations like function inlining.
If you have highly performance sensitive code it is best not to use this library, particularly in functions that are not benchmarked.
The following form introduces no overhead in all Go versions:
x, err := f()
try.Check(err)By default, try.Check* will wrap the error so that it has a stack trace
This can be disabled by setting the AddStackTrace = false
By default. Handle* will annotate panics as well.
This can be disabled by setting AnnotatePanics = false
try has the following package structure:
- The top-level main package try can be imported as try which combines both the try/handle and try/try packages
- The
try/handlepackage includes error recovery functions. - The
try/trypackage offers error checking functions that return errors. - The
stackprintpackage contains the original code fromerr2to help print stack traces - The
assertpackage contains the original code fromerr2to help with assertions.