Warning
The project is not production ready and very experimental.
Motivation
When developing a software application error messages tend to be an afterthought or forgotten all together, which in turn
might make for a poor user experience when troubleshooting errors. With error.fyi I hope to improve the story around error messaging
and troubleshooting.
An error wrapped using error.fyi's client libraries, should always be able to answer the following:
- What caused the issue?
- How they could solve the issue.
- What to do to solve the issue.
π Features
- Provides application users with better context for troubleshooting errors.
- Easy integration with existing Go applications.
- Provides in-code documentation generation.
- Simple markdown documentation generation.
- Supports custom markdown templates.
(back to top)
π Get Started
Get started by installing error.fyi CLI, fyictl.
curl -sfL https://raw.githubusercontent.com/error-fyi/fyictl/main/install.sh | sh -
and importing the Go client library.
go get -u github.com/error-fyi/go-fyi@latest
Add additional error context
Once the previous prerequisites are met you should be ready to use fyictl to add more context
to the errors in your Go projects.
We'll use this simple program, with only the main.go
, to demonstrate the tool's utility.
package main
import (
"errors"
"log"
)
func main() {
err := doSomething()
if err != nil {
log.Fatal(err)
}
}
func doSomething() error {
// TODO improve this error message
err := errors.New("something went wrong, please try again")
return err
}
The program will print an error to the user telling them something went wrong. Although polite the error message
isn't answering the question a user might have when encountering an error:
- What caused the issue?
- How they could solve the issue.
- What to do to solve the issue.
Now let's use fyictl to improve thing.
From your terminal window in the Go project directory run the following:
fyictl init --wrap
Tip
To configure fyictl to target errors with a TODO prefix you can add the --todo
flag, like in the example:
fyictl init --wrap --todo
Now the program should look something like this:
package main
import (
"errors"
"log"
fyi "github.com/error-fyi/go-fyi"
)
// @fyi name <CHANGE ME>
// @fyi title <CHANGE ME>
// @fyi base_url <CHANGE ME>
// @fyi version v0.1.0
// @fyi description <CHANGE ME>
func main() {
err := doSomething()
if err != nil {
log.Fatal(err)
}
}
func doSomething() error {
// TODO improve this error message
err := errors.New("something went wrong, please try again")
// @fyi.error code main_error_18
// @fyi.error title <CHANGE ME TO A NICE TITLE>
// @fyi.error short <TL;DR ON THE CAUSE OF THE ERROR>
// @fyi.error severity severe|medium|low
// @fyi.error.suggestion short <TL;DR ON HOW CAN THE ERROR BE FIXED?>
return fyi.Error(err, "main_error_18")
}
The tools ha done a few things:
- Has added annotations above the
main()
with fields to describe the application.
- Has added annotations around the error, that add additional context to the error.
- Has wrapped the returning error with the error.fyi error wrapper.
All the annotation values can be updated, even the error code, but for this example we'll limit to updating the
required fields. More information about the annotations is available here.
Init command can be used for already existing projects, and it will recursively explore the packages for errors.
Tip
fyictl also provides an annotate command which annotate a single file
fyictl annotate -f main.go
package main
import (
"errors"
"log"
fyi "github.com/error-fyi/go-fyi"
)
// @fyi name example-app
// @fyi title Example App
// @fyi base_url docs.example.com
// @fyi version v0.1.0
func main() {
err := doSomething()
if err != nil {
log.Fatal(err)
}
}
func doSomething() error {
// TODO improve this error message
err := errors.New("something went wrong, please try again")
// @fyi.error code main_error_18
// @fyi.error title Transaction Error
// @fyi.error short There was an error during transaction, value exceeded limit
// @fyi.error severity low
// @fyi.error.suggestion short Retry the transaction with a lower input value
return fyi.Error(err, "main_error_18")
}
Now we can generate the application error manifest, this a yaml manifest containing information about the different errors
in an application.
From the terminal run:
fyictl manifest -o errors.yaml
The following our simple program application error manifest.
Example error manifest.
---
# Code generated by fyictl: https://github.com/tfadeyi/errors.
# DO NOT EDIT.
base_url: docs.example.com
errors_definitions:
main_error_18:
code: main_error_18
meta:
loc:
filename: main.go
line: 24
severity: low
short: There was an error during transaction, value exceeded limit
suggestions:
"1":
error_code: main_error_18
id: "1"
short: Retry the transaction with a lower input value
title: Transaction Error
name: example-app
title: Example App
version: v0.1.0
Once we have the manifest we can embed it into our application and make it available at runtime.
package main
import (
"errors"
"log"
_"embed"
fyi "github.com/error-fyi/go-fyi"
)
//go:embed errors.yaml
var errorsYAML []byte
// @fyi name example-app
// @fyi title Example App
// @fyi base_url docs.example.com
// @fyi version v0.1.0
func main() {
fyi.Manifest(errorsYAML)
err := doSomething()
if err != nil {
log.Fatal(err)
}
}
func doSomething() error {
// TODO improve this error message
err := errors.New("something went wrong, please try again")
// @fyi.error code main_error_18
// @fyi.error title Transaction Error
// @fyi.error short There was an error during transaction, value exceeded limit
// @fyi.error severity low
// @fyi.error.suggestion short Retry the transaction with a lower input value
return fyi.Error(err, "main_error_18")
}
Let's now run our simple application:
Example error output.
$ go run main.go
2023/10/03 22:46:12 [something went wrong, please try again]
TRANSACTION ERROR
## What caused the error
There was an error during transaction, value exceeded limit
## Quick Solutions
β Additional information is available at: docs.example.com/example-
β app/errors/main_error_18
β’ Suggestion: Retry the transaction with a lower input value
exit status 1
Generate Markdown Documentation
fyictl
also allows you to further generate markdown documentation based on the error manifest.
fyictl docs generate -f errors.yaml
This will generate the markdown documentation under the default directory ./docs
.
Tip
You can change the output directory by specifying the flag --output
followed by the directory you want to target.
.
βββ docs
βΒ Β βββ main_error_18.md
βββ index.md
1 directory, 2 files
Example of `index.md` contents.
---
title: example-app
---
## example-app
**Application**: example-app
**Version**: v0.1.0
### Error definitions
* [**main_error_18**](./errors/main_error_18): There was an error during transaction, value exceeded limit
Example of `error definition`.
---
title: Transaction Error
code: main_error_18
---
## Transaction Error
**Code**: main_error_18
### Summary
There was an error during transaction, value exceeded limit
Expose Documentation
Once the documentation is generated you can use tools like GitHub Pages to host and expose it to your application's
users.
GitHub Pages
Check GitHub's docs for how to setup a static page.
Make sure to set the Custom Domain value to match what was defined in @fyi base_url docs.example.com
.
(back to top)
License
error.fyi is released under the MIT License.
(back to top)