Skip to content

proposal: change for Go beginners (stack trace) #140

@pierrre

Description

@pierrre

What I understand

  • WithMessage() adds a message
  • WithStack() adds the current stack
  • Wrap[f]() adds a message + stack
  • New|Errorf() creates an new error with message + stack

History

If I remember correctly:

  • Wrap[f]() was added first
  • WithMessage() + WithStack() were added later, because Wrap[f]() was "too much" => we don't need a stack trace for all "wrapped error". It is only useful for the "deepest" error.

When should we use each function

  • New root error => New|Errorf() (it will contain a stack trace)
  • Error returned by the std lib or a 3rd party lib => Wrap[f]() (we want to add a stack trace)
  • Error returned by our own code (in my app) => WithMessage() (we don't want to add more stack trace)
  • Error returned by a different goroutine => WithStack() (I don't use it very often)

Who am I working with

  • ~10 Go developers
  • All beginners in Go (they were working with other languages previously)
  • Not always very strict/careful

The problem

  • They don't/can't understand where to use Wrap[f]() vs WithMessage()
  • We're losing a lot of time during code review
    • Checking if Wrap[f]() or WithMessage() should be called
    • Explaining in which case we must use which function
    • Starting again for each newcomer

The risks

  • If we call WithMessage() instead of Wrap[f]() => we're missing the stack trace
  • If we call Wrap[f]() instead of WithMessage() => we "pollute" our error logs

What we need

A function that wraps an error with a message, and optionnaly with a stack trace if it doesn't have already one.

What I tried

My initial idea was to write a custom helper function that would do as described previously.
Sadly, this is not easily doable.
I can't call WithStack() or Wrap[f]() because it would include the helper function call in the stack.

The solutions

New function

Add a new function to github.com/pkg/errors, that is exactly like Wrap[f](), but doesn't add a stack trace if there is already one.

I don't really like this one, because it makes the package's interface more complex

Change behavior

Change Wrap[f](), and don't add a stack trace if there is already one.

This is my favorite solution.

I agree, it will change the existing behavior.
However, I think this is worth it.
I can't think of any use case that requires to call Wrap[f]() several times and have several redundant stack traces.

Just fork

I can perfectly understand if you disagree, and don't want to update the current code.
In this case, I will just copy the code to our internal repo, and adapt the code to match our needs.

I don't really like this, because I would stop using github.com/pkg/errors.
We're currently using it everywhere in our code.
I've been able to "extend" the behavior properly since the beginning.

The implementation

I've seen #122 and I really dislike the implementation.
It means that only internal github.com/pkg/errors types can be used.
We can't create our own types anymore.

What I would do instead:

  • iterates over all causes
  • check if at least 1 error implements StackTrace()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions