Error Handling Revamp === ## Overview Displaying and reporting errors in Prysm should be as user-friendly as possible. We must make sure that users are able to include the stack trace in Github issues and that the error logs we provide are informative, helpful and, most of all, **not too scary**. This document outlines a few ideas to make everyone's "error life" easier. ## Improvements ### 1. Use `github.com/pkg/errors.New` instead of `errors.New` Errors created with`errors` include only a message, whereas errors created with `github.com/pkg/errors` include also a stack trace, which is much better for debugging and logging. There is no reason to use `errors.New`. **Action Items** - Replace usages of `errors.New` with `github.com/pkg/errors.New` in the existing codebase. - Write a static analyzer similar to `cryptorand` that will trigger an error whenever `errors.New` is used. ### 2. Use `log.Error(err)` for logging and `fmt.Sprintf("%+v\n", err)` to dump the stack trace to a log file As described in the "Fprint and Print have been removed" section of https://dave.cheney.net/2016/06/12/stack-traces-and-the-errors-package, the `%+v` formatting verb can be used to print an error from `github.com/pkg/errors`, including the stack trace. Instead of scaring the user the stack trace, we can log out the message string and save the whole stack trace to a file on disk. These log files can be then uploaded onto Github as attachments to issues. **Action Items** - Use the `log.Error(err)` + `fmt.Sprintf("%+v\n", err)` pattern in `main` and goroutines. - Extract the pattern to a helper function in a shared package. **Open Questions** - Where to store log files for each system? ### 3. Make error messages more user-friendly Users should be informed what actions they can take when they encounter an error. Simply displaying the error message is not enough, especially if the stack trace, which is much more useful for debugging, gets saved to a log file. **Action Items** - Wrap all error logs in a standard, user-friendly information. This information should include the path to the saved log file, a link to Github and basic instructions on what to do next. ### 4. Do not store errors in package-level variables Consider the following example: ``` package foo import ( "github.com/pkg/errors" ) var e = errors.New("error from foo") // line 7 func F() error { return e } ``` Calling this function results in a stack trace such as this: ``` error from foo github.com/prysmaticlabs/prysm/beacon-chain/foo.init beacon-chain/foo/foo.go:7 // line of declaration, not line of error! runtime.doInit GOROOT/src/runtime/proc.go:6265 runtime.doInit GOROOT/src/runtime/proc.go:6242 runtime.doInit GOROOT/src/runtime/proc.go:6242 runtime.main GOROOT/src/runtime/proc.go:208 runtime.goexit GOROOT/src/runtime/asm_amd64.s:1371 ``` The stack trace displays information from the time when the error was created, which is during package intialization. This is definitely not useful. The "Sentinel errors" section in https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully describes such errors as an anti-pattern. **Open Questions** - This pattern is used extensively throughout the codebase and changing it would require a lot of work. Is it worth it? - How exactly can this pattern be replaced? Is there a one-size-fits-all solution or will we have to proceed case by case?