Verbose Error Handling

A brief overview of the `eh` package.

Cheikh seck
Stackademic

--

https://unsplash.com/photos/heNwUmEtZzo — By David Pupăză

I’m as much of a fan of the Go programming language as the next Gopher, but I sometimes find myself having trouble finding the origin of an error within a function that can generate/return different types of potential errors. To better articulate this issue, let’s look at the following code:

func TestErrUseCase(t *testing.T) {

var err2, err3, err4 error

_, err2 = db.Dial()
if err2 != nil {
t.Log(eh.Err(err2))
}

_, err3 = db.Email()
if err3 != nil {
t.Log(eh.Err(err3))
}

err1 := eh.Err(
errors.New("Test err"),
)

if err1 != nil {
t.Log(eh.Err(err1))
}

err4 = db.Close()
if err4 != nil {
t.Log(eh.Err(err4))
}

}

The test function defined above performs numerous error checks — upon logging the error, I’m invoking the eh package’s Err function and by doing this I’ll append the line number (of where I’m calling the Err function from) to the error message. In the past, I’d try to add different log messages around the suspected area; but moving forward, I’ll use the eh package to get more information about an error message, instantly.

One thing I’d like to point out is how crucial it is to not return source code information as error messages for a consumer-facing API.

The eh Package

I broke after a few restless nights trying to keep myself from looking at the slog package’s source code; I cracked and decided to figure out how can a Go program determine the line number/file of a piece of code.

In my opinion, the implementation was straight-forward. The Go team leverages the runtime package to get information about the current execution stack and determine the line and file from the frames returned.

Listing 1

01 package main
02
03 import (
04 "errors"
05 "log"
06
07 "github.com/cheikh2shift/eh"
08 )
9
10 func main() {
11
12 if err := run(); err != nil {
13 log.Println(
14 err,
15 )
16 }
17 }
18
19 func run() error {
20 err1 := errors.New("Error 1")
21
22 log.Println(
23 eh.Err(err1),
24 )
25
26 eh.Log(err1)
27
28 err2 := eh.Err(errors.New("Error 2"))
29
30 return err2
31 }
32

Listing 1 demonstrates how the eh package can be used to get the line number and file of where its Err function is called from. In line 26, I’m using a utility function to directly log an error to the console with the line number of where I’m calling the Log function from.

Figure 2

Figure 2 depicts the output generated by the code in listing 1. As expected, the line number, file and function calling the Err function is displayed. Similar to the slog package, there is an issue with abstracting the functions in this package; however, I’ll add a variadic parameter to the Err function that will enable developers to adjust the depth value for their use case.

Conclusion

I believe that adding source code information to certain error messages is ideal for certain use cases; in some, it will expose sensitive information. Although error handling in Go is simple for most cases it becomes a nightmare when you have error objects being propagated with each function call.

To learn more about the eh` package, click on the card below:

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.

--

--