Repository navigation
Formatting: Simple multi-error format #74
Description
Activity
+1 on formatting customization options.
I'd also like to experiment with an option to deduplicate the error messages in the tree for common uses of
errors.Join.So here's my thinking:
Tree representation is not actually useful.
Nobody wants an ASCII error representation in their error output.
They either want structured information (which is now possible with #102),
or they want simple readable output.I propose that we change Format and FormatString to do empty-line-separated errors for multi-errors.
So the trace for a single error chain is:error message path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42 ...And the trace for a multi-error is:
error message 1 path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42 ... error message 2 path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42 ... ...This matches the simplicity of
errors.Join, which does newline-separated messages.
Anything more customizable can be done withUnwrapFramedirectly.If anyone actually finds the tree functionality useful, we can put it in a FormatTree function.
Thoughts?
Edit: Update:
Tried it out. The output doesn't look good if we also print the multi-error.
You end up with:err 1 err 2 err 3 err 1 path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42 err 2 path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42 err 3 path/to/package.Func path/to/file.go:42 path/to/package.Func path/to/file.go:42The above case looks better if we don't print the multi-error itself (which makes sense since we're traversing its children), but it loses information if there was a trace leading up to the multi-error.
Example from playing around:
Flat:
std err 1 std err 2 std err 3 std err 4 braces.dev/errtrace_test.Example_tree /path/to/errtrace/example_tree_test.go:2 std err 1 std err 2 braces.dev/errtrace_test.wrapNormalErr /path/to/errtrace/example_tree_test.go:1 std err 3 std err 4 braces.dev/errtrace_test.wrapNormalErr /path/to/errtrace/example_tree_test.go:1Tree:
+- std err 1 | +- std err 2 | | braces.dev/errtrace_test.wrapNormalErr | /path/to/errtrace/example_tree_test.go:1 | | +- std err 3 | | | +- std err 4 | | | | braces.dev/errtrace_test.wrapNormalErr | | /path/to/errtrace/example_tree_test.go:1 | | +- std err 3 | std err 4 | std err 1 std err 2 std err 3 std err 4 braces.dev/errtrace_test.Example_tree /path/to/errtrace/example_tree_test.go:2
The tree output format should be opt-in, and we should default to just empty-line-separated leaf errors.
For leaf errors, multi-error parent just provides an additional piece of the error trace, so there will be some repetition of frames between those errors.
This also ties into #71: we can expose a simple iterator
func(error, []frame)with the understanding that parent/child relationships don't need to be exposed.