3

I'd like to trace the execution path of an arbitrary Node.js program.

Specifically, I'd like to run a program (server or script), and have some sort of block-level (function call, loop, if statement) trace of the execution.

Constraints

  • Output must contain files / lines / hit count for all lines during execution
  • No code minification. Istanbul is great but I want to keep the code that is executed in the end as readable as possible.
  • For long-running processes (servers, for example), I want to be able to see "current" line coverage (or as up-to-date as possible)
  • I don't want to lose any coverage data, so while Profiling would give me some hints as to lines hit, it's not really code coverage.

Things I don't care about

  • Exactly how the coverage is read. For example, it could be output to a file, it could be read via the code, etc.
  • Coverage format

Thing's I've investigated so far:

Using NODE_V8_COVERAGE:

I found that if I set the NODE_V8_COVERAGE environment variable to a directory, coverage data will be output to that directory when the program exits (here's a blog post on the creation of this feature).

The problem that I'm facing here is that I'm not sure there's a way to trigger the generation of these reports before the program terminates.

Using inspector

I have also been experimenting with Node.js inspector. I found a useful CPU profiler here. This could end up being helpful, but this profiler works by sampling, not as a hook into the language. As a result, I only get line numbers / counts for parts of the code that were slow.

I also tried using Profiler.startPreciseCoverage, thinking that somehow this might give me every line that was executed (didn't find the documentation to be clear on what this does really). It didn't seem to be any more useful

Using Istanbul

I would like to avoid instrumenting code if possible.

Question

It seems like my options are limited, but at the same time this is only a result of my Googling for an hour or two.

Is there a better way to capture line coverage with the constraints listed above?

wheresmycookie
  • 683
  • 3
  • 16
  • 39
  • I'm not sure to fully understand your requirements, but have you tried running your script / server with ndb (https://github.com/GoogleChromeLabs/ndb) ? You can add breakpoints to stop the execution at a specific point and inspect the scope. But more important to you : you can record performance and it gives you some kind of FlameGraph. You can also profile memory usage with it. It's chrome devtools, but for nodejs – boehm_s Oct 05 '20 at 09:49
  • The difference between precise coverage (`startPreciseCoverage`) and best-effort coverage is covered at https://v8.dev/blog/javascript-code-coverage. IIUC, precise coverage keeps counts for functions that go out of scope whereas best-effort coverage loses that information. – Trott Oct 06 '20 at 21:09
  • If you had to add a line of code to your app to cause the current coverage to be written out, would that meet your needs? – Trott Oct 06 '20 at 21:58
  • @Trott that would be ok! Adding a few lines isn't a dealbreaker – wheresmycookie Oct 07 '20 at 15:14

1 Answers1

0

There's a pull request pending for Node.js to add functionality to programmatically start/stop/write V8 coverage information. If you are adventurous, you could use git to get the version of Node.js you want to use, apply the commits from the patch, and compile a Node.js binary.

If you clone the Node.js repository, the various versions of Node.js are tagged. So you can get the code for Node.js 12.19.0 by checking out the v12.19.0 tag.

You can cherry-pick the commits from the pull request normally, or you could use curl -L https://github.com/nodejs/node/pull/33807.patch | git am to apply the commits as patches.

Instructions for compiling/building the Node.js binary can be found at https://github.com/nodejs/node/blob/master/BUILDING.md#building-nodejs-on-supported-platforms.

More long term, you could chime in on the pull request on whether it meets your needs or not and hopefully get it going again. It seems to have stalled.

Trott
  • 66,479
  • 23
  • 173
  • 212