Skip to content

Formatting: Simple multi-error format #74

Description

@abhinav

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.

Activity

  1. prashantv commented on Dec 12, 2023

    @prashantv
    Contributor

    +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.

  2. abhinav commented on May 4, 2024

    @abhinav
    ContributorAuthor

    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 with UnwrapFrame directly.

    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:42
    

    The 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.

  3. abhinav commented on May 4, 2024

    @abhinav
    ContributorAuthor

    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:1
    

    Tree:

    +- 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
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions