Add support for optional extra context messages in errors
Support has been added to error handling allowing for optional messages containing extra context to be added to an error and displayed when it surfaces. This applies to both standard errors and obfuscated errors.
Four new methods have been added to facilitate this additional flexibility:
-
AddMsg(err error, msg string) []error
- This method takes an error and a string containing an extra context message. The extra context string is used to build a new error, and both this and the other error passed into the method are then used to build a slice of errors. -
AppendMsg(errs []error, msg string) []error
- Similar toAddMsg
, a string containing an extra context message is passed into the method, used to create an error, and added to a slice. However, this method should be used if the extra context string is intended to be appended to an already existing slice of errors. As Go intentionally does not support appending errors by way oferrors.Join()
, this method is necessary if we want to collect an undetermined number of errors/messages that we might want to combine into a single error later on in the error handling process. -
JoinErrs(errs []error) error
- This method can be used to combine a slice of errors created by eitherAddMsg
orAppendMsg
into a single error. This can be helpful when we want to pass an error with multiple extra context messages between methods which only support a single error. Additionally, unlike error wrapping, joining the errors using the functionality provided in Go v1.20 allows us to keep and potentially reuse all layers of the original slice after unwrapping, which is especially helpful when constructing the surfaced error message containing both the original/obfuscated error along with any number of additional context messages. -
UnwrapJoinErrs(err error) []error
- In this method, we find out if an error is a joined error by creating a conditional checking that the error can type assert an interface type holding theUnwrap() []error
method. If the error can not have this interface type asserted to it, then the method will returnnil
. Otherwise, the error will be unwrapped and the errors within, including the extra context message(s), will be returned as a slice.
After processing an error with extra context messages using the methods provided above, a message will be constructed. If a joined error is passed into the message building stage, it will be unwrapped into a slice. The first element of the slice is the original error encountered, and each remaining element is an extra context message. The original error goes through the checks for obfuscation or user safe messages the same way as previously. Each element of the slice containing extra context messages is then appended as a bullet point to the resulting original error message, for an output that will look something like:
Error encountered during job: user auth error
* extra context 1
* extra context 2
---
* extra context n
Appropriate tests have also been added to ensure this extra flexibility works as intended.