159 lines
3.3 KiB
Markdown
159 lines
3.3 KiB
Markdown
# adverr
|
|
|
|
Package adverr implements errors with call stack traces
|
|
as well as error templates for error equality
|
|
|
|
## Installation
|
|
```
|
|
go get git.tordarus.net/tordarus/adverr
|
|
```
|
|
|
|
## Usage examples
|
|
|
|
### Import
|
|
```go
|
|
import "git.tordarus.net/tordarus/adverr"
|
|
```
|
|
|
|
### Create error templates
|
|
```go
|
|
var (
|
|
ErrDoStuffFailed = adverr.NewErrTmpl("ErrDoStuffFailed", "Could'nt do stuff because of %s")
|
|
)
|
|
```
|
|
|
|
### Create independent error (without error template)
|
|
```go
|
|
func doStuffWithIndependentErr() error {
|
|
return adverr.New("Could'nt do stuff")
|
|
}
|
|
```
|
|
|
|
### Create error based on template
|
|
```go
|
|
func doStuff() error {
|
|
return ErrDoStuffFailed.New("reasons")
|
|
}
|
|
```
|
|
|
|
### Print errors on stderr convieniently
|
|
```go
|
|
adverr.Print(myErr)
|
|
adverr.Println(myErr)
|
|
```
|
|
|
|
### Print errors on stderr and exit with exit code
|
|
```go
|
|
adverr.Fatal(myErr, 1)
|
|
adverr.Fatalln(myErr, 1)
|
|
```
|
|
|
|
### Advantages of error templates
|
|
two errors made by the same template will return true when called with `errors.Is()`
|
|
```go
|
|
func doStuffAndFailWithMsg(msg string) error {
|
|
return ErrDoStuffFailed.New(msg)
|
|
}
|
|
|
|
err1 := doStuffAndFailWithMsg("err1")
|
|
err2 := doStuffAndFailWithMsg("err2")
|
|
|
|
fmt.Println(errors.Is(err1, err2)) // true
|
|
fmt.Println(err1 == err2) // false
|
|
fmt.Println(err1.Error() == err2.Error()) // false
|
|
```
|
|
|
|
### Wrap errors (Causality of errors)
|
|
By wrapping errors, you can provide an error that is caused by another error.
|
|
A 'Caused by' section will be printed in the stack trace showing the original error.
|
|
You can also retrieve the original error by using `errors.Unwrap()`
|
|
```go
|
|
func doStuffWrapped() error {
|
|
err := doStuff()
|
|
if err != nil {
|
|
return adverr.Wrap("doStuffWrapped failed", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
### Retrieve call stack trace (for debugging purposes)
|
|
```go
|
|
fmt.Println(adverr.Trace())
|
|
```
|
|
|
|
### Example of a printed error
|
|
Code:
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"adverr"
|
|
"errors"
|
|
)
|
|
|
|
var (
|
|
ErrDoStuffFailed = adverr.NewErrTmpl("ErrDoStuffFailed", "Could'nt do stuff because of %s")
|
|
)
|
|
|
|
func main() {
|
|
err := doStuffInAnotherGoroutine()
|
|
if err != nil {
|
|
adverr.Fatalln(err, 1)
|
|
}
|
|
}
|
|
|
|
func doStuff() error {
|
|
err := doGoNativeStuff()
|
|
if err != nil {
|
|
return ErrDoStuffFailed.Wrap(err, "reasons")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func doStuffInAnotherGoroutine() error {
|
|
ch := make(chan error, 1)
|
|
|
|
go func() {
|
|
ch <- doStuff()
|
|
close(ch)
|
|
}()
|
|
|
|
err := <-ch
|
|
if err != nil {
|
|
return adverr.Wrap("Goroutine failed because of errors", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func doGoNativeStuff() error {
|
|
return errors.New("some go error")
|
|
}
|
|
|
|
```
|
|
Output:
|
|
```
|
|
adverr.Error: Goroutine failed because of errors
|
|
at main.doStuffInAnotherGoroutine (/home/user/go/src/test/main.go:38)
|
|
at main.main (/home/user/go/src/test/main.go:13)
|
|
at runtime.main (/usr/local/go/src/runtime/proc.go:204)
|
|
Caused by ErrDoStuffFailed: Could'nt do stuff because of reasons
|
|
at main.doStuff (/home/user/go/src/test/main.go:22)
|
|
at main.doStuffInAnotherGoroutine.func1 (/home/user/go/src/test/main.go:32)
|
|
Caused by errors.errorString: some go error
|
|
(Unknown source)
|
|
```
|
|
|
|
### Globals
|
|
You can set the maximum limit of the call stack trace via
|
|
```go
|
|
adverr.CallStackLength = 50 // default value: 100
|
|
```
|
|
|
|
If you are in a productive environment, consider disabling call traces completely for performance reasons:
|
|
```go
|
|
adverr.DisableTrace = true // default value: false
|
|
``` |