# 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 ```