Skip to content

Retain (most of) Node.js internals in stack traces #2420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 23, 2020
Merged

Retain (most of) Node.js internals in stack traces #2420

merged 15 commits into from
Apr 23, 2020

Conversation

bunysae
Copy link
Contributor

@bunysae bunysae commented Mar 9, 2020

Fixes issue #2110. The node internal stack trace is shown for error originated from Node.js. If it's originated from custom code, node internal stack traces are culled out.
The code-property is shown in node v12.16.1 without any modification to ava-source-code. In older versions (i had v12.10.0) before, the code-property wasn't a enumerable property and therefore doesn't appear.


IssueHunt Summary

Referenced issues

This pull request has been submitted to:


IssueHunt has been backed by the following sponsors. Become a sponsor

@novemberborn
Copy link
Member

Thanks for your PR @bunysae. I did not open my editor this weekend so I haven't had time yet to look into this, sorry.

@novemberborn
Copy link
Member

I've spent some time trying to figure out what we're trying to do here. #2110 is an older issue, we recently came to the conclusion that it'd be good to show all lines, but use colors to indicate the less relevant ones. See #2412 for that discussion.

That's probably more than we need to deal with in this PR. However as you probably found the code here is rather messy.

I suspect we can remove clean-stack, and rely solely on stack-utils. We haven't kept pace with the changes in stack-utils so we need to make better use of its current features.

There's another mess in lib/serialize-error.js which ends up relying on the beautified stack trace:

stack = beautifyStack(stack);


Going by your test, the output for a file like this:

const path = require('path')
const test = require('ava')

test('foo', t => {
  path.resolve({root: '..'})
  t.pass()
})

Goes from:

npx ava -v

  ✖ foo Error thrown in test

  1 test failed

  foo

  test.js:5

   4: test('foo', t => {
   5:   path.resolve({root: '..'})
   6:   t.pass()

  Error thrown in test:

  TypeError (NodeError) {
    code: 'ERR_INVALID_ARG_TYPE',
    message: 'The "path" argument must be of type string. Received type object',
  }

To:

npx ava -v

  ✖ foo Error thrown in test

  1 test failed

  foo

  internal/validators.js:112

  Error thrown in test:

  TypeError (NodeError) {
    code: 'ERR_INVALID_ARG_TYPE',
    message: 'The "path" argument must be of type string. Received type object',
  }

  validateString (internal/validators.js:112:11)
  Object.resolve (path.js:980:7)
  test.js:5:8
  processTicksAndRejections (internal/process/task_queues.js:94:5)

Note how we're no longer showing the test code in the error output. Arguably, the error did not originate in Node.js, but it originated in the test.

#2110 describes a situation where the error occurred asynchronously, outside of a test invocation.


Probably the right approach here is to simplify the error formatting and the various ways in which we munge the stack, and then see how errors end up being reported. What do you think @bunysae?

@bunysae
Copy link
Contributor Author

bunysae commented Mar 22, 2020

@novemberborn
I understand your problem with this PR. When i understand the discussion in #2412 correctly, you want still cull out ava internal stack lines and give the user and node internal stack lines different colors?
I think i can do this with the chalk-lib.

@novemberborn
Copy link
Member

When i understand the discussion in #2412 correctly, you want still cull out ava internal stack lines and give the user and node internal stack lines different colors?

Yes. However this is made more difficult due to mess I described above. We should try and clear that up first.

@bunysae
Copy link
Contributor Author

bunysae commented Mar 24, 2020

I refactored this PR. Now the complete stack-trace is shown except:

  • ava internals,
  • ava dependencies
  • the node internals internal/process/task-queues and internal/modules/cjs/loader (They add noice to ava assertion errors and errors thrown due to impromper test files).
    Node internals are grey. Custom-code has the default color.

I also added an option to cull out node internals. This is useful for the CI-Build as well as for developers, how want to have the current behavior.

How to you want the show the code-excerpt? In the path-example above, the code excerpt would be still omitted. Should ava always show an excerpt of the deepest layer (custom-code)?

@novemberborn
Copy link
Member

@bunysae thanks for the update. I'll try and have a look at this on the weekend.

Copy link
Member

@novemberborn novemberborn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the complete stack-trace is shown except:

  • ava internals,
  • ava dependencies
  • the node internals internal/process/task-queues and internal/modules/cjs/loader (They add noice to ava assertion errors and errors thrown due to impromper test files).
    Node internals are grey. Custom-code has the default color.

👍

I also added an option to cull out node internals. This is useful for the CI-Build as well as for developers, how want to have the current behavior.

I don't think we need that just yet. Let's see how folks get on seeing more stack trace lines.

The reporter tests can be quite tricky to get working across the Node.js versions and OS. I can help with that.

P.S. the worker processes have access to an options object, there's no need to use additional environment variables.

How to you want the show the code-excerpt? In the path-example above, the code excerpt would be still omitted. Should ava always show an excerpt of the deepest layer (custom-code)?

I think we should update serialize-error to go through the stack trace and find the first call site that came from the test file, and then show that.

@bunysae
Copy link
Contributor Author

bunysae commented Apr 4, 2020 via email

@novemberborn
Copy link
Member

My idea to handle the stack-traces of different nodes.js versions and OSes is to create different log-files for every combination. Then we wouldn't had a problem with a failing CI-build.

Yes, sounds good. It'll be a bit harder to update the files, but that should still be easier than trying to string-replace away the differences.

@bunysae
Copy link
Contributor Author

bunysae commented Apr 14, 2020

I moved the stack processing to the reporters and splited the log-files for the three major node versions.

@novemberborn
Copy link
Member

@bunysae awesome! It probably won't be until the weekend that I'll have a chance to look at this though.

* Use the ignoredPackages option from stack-utils
* Ignore all cjs internals
* Keep ignoring some Node.js internals (there's useful stuff here:
https://github.com/tapjs/stack-utils/blob/d3c7ee2a7d46744c271a36ce3acfd69465f36df5/index.js#L12-L18)
* Return an array of lines
* Remove dedicated tests, rely on reporter integration tests instead
Dim internal lines, leave normal lines as grey. Add a pointer so it
looks a bit more like a list of lines
Copy link
Member

@novemberborn novemberborn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bunysae I've made a bunch more changes but I think this is ready now. Would you mind reviewing my changes?

There's two review comments below but they're already outdated.

(Let's see if I managed to not break the tests…)

// The `callSite.file` property is platform independent (with '/' as directory separator)
// and `testFile` is platform dependent (on win32 with '\' as directory separator).
if (callSite.file === path.relative(process.cwd(), testFile).split(path.sep).join('/')) {
result = callSite;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how this tries to find the first call site in the test file. However this takes the last call site, rather than the first. Is that intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No that wasn't intentional. I didn't realize that.

let result = null;
stack.split('\n').forEach(line => {
try {
const callSite = stackUtils.parseLine(line.replace('file:///', '/'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are meant to have come from esm but I can't reproduce that anymore, at least not for the use case of extracting the source within the test file.

Copy link
Contributor Author

@bunysae bunysae Apr 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file:/// is replaced to pass the test (https://github.com/bunysae/ava/blob/7c5ebac7adb4183393d02ee6e6f5b237e5f6aa1e/test-tap/serialize-error.js#L128). I can try it out, if the actual esm version still inserts file-urls. If not, i think we can omit it.

@bunysae
Copy link
Contributor Author

bunysae commented Apr 19, 2020

@novemberborn Except the open-point with the esm file-url's it looks goods. Didn't find more todos in my review.

@novemberborn
Copy link
Member

Except the open-point with the esm file-url's it looks goods. Didn't find more todos in my review.

I couldn't reproduce that problem with the latest esm so I think we're good!

@novemberborn
Copy link
Member

I'm just asking some folks for feedback outside of GitHub. Stay tuned 😄

@novemberborn novemberborn changed the title Show node internal stack trace Retain (most of) Node.js internals in stack traces Apr 23, 2020
@novemberborn novemberborn merged commit 9a9351d into avajs:master Apr 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants