jaridmargolin / inspect-process

🔍 Dead simple debugging for node.js using chrome-devtools.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possible support for child processes

jaridmargolin opened this issue · comments

It may be possible to monkey patch child_process methods to force inspect. I would almost always consider this bad practice, but perhaps it could live behind a flag --patch or --inspect-children?

The underlying question being if the ease of use this is worth the potential unknown edge cases it may create.

Known Complexities

  • Finding an available port would not be possible with our current implementation. spawn is expected to immediately return the process but portfinder resolves asynchronously.

  • Altering the std spy/filter to manage the lifecycle of these spawned child processes may be difficult. I'm fairly certain it can done, but there is definitely a question of how hacky/reliable the solution would be.

So, this is a node.js problem. I'm guessing that we're not the first to require debugging of child processes.

If node provides a debugging feature and it provides a child process feature, it should extend the debugging feature to the child process feature. Is how I see it.

In another thought, if we run node with NODE_DEBUG environment variable set, do we get through the printed information what we required to start a debugging session on the child process, or is it not only information that is required, but control of the spawn call, itself?

https://github.com/nodejs/node/blob/49d1c366d85f4b7e321b1d71eabaae59c20b83c5/lib/child_process.js#L383

Is this going to help with the portfinder issue?
nodejs/node#5025

I've requested a feature that may solve this issue upstream in Node.js:
nodejs/node#9621

Thanks for info/followup @mightyiam. I am following the relevant discussions and will try to address ASAP.

May be a good place to start: https://github.com/tapjs/spawn-wrap

Oh, the things we do...

@mightyiam spawn-wrap is used under the hood for istanbul/nyc which gives me a high degree of confidence it will be stable/resilient enough for our use case. Fairly excited to stumble on it.

Yes, spawn-wrap is designed for this exact purpose, and works surprisingly well, apart from a few caveats. (I say "surprisingly", because it's so hacky that it's practically a miracle it works at all.)

Most notably, using two spawn wraps at once is not possible at this time.

@jaridmargolin I'm not familiar enough with the project to know whether this tip will be helpful, but I've had success propagating the --inspect flag to child processes created with fork instead of spawn, via the execArgv option:

child_process.fork(path, args, {
    env: process.env,
    cwd: process.cwd(),
    execArgv: ['--inspect']
})

Last unknown is how to best integrate with devtools at an interface level. Will I need to open a new tab/window for every child_process, or is there a way for a single devtools session to listen on multiple ports? I know it is possible to debug nodejs in parallel with browser js.

@paulirish - Any chance you could provide insight into current capabilities?

I'd like to set some time aside over the next week or so to attack this issue.

is there a way for a single devtools session to listen on multiple ports?

Yes definitely. :) . @pavelfeldman and I just walked through this flow and it looks reasonable.

You can see it normally with web workers:
image

and yeah its a very similar thing to do the parallel debug.

You'll have to MITM the protocol traffic. Looks like you're not doing that now, but in order to convince devtools it has multiple targets to debug simultaneously, you'll have to talk the talk.

So DevTools will connect over 9222 (or whatever) to inspect-process's websocket. then typically you just pass through all messages to the node child_process but in some cases, you'll issue extra events to devtools and respond to methods differently.

The target domain is what enables devtools to connect to all this stuff: https://chromedevtools.github.io/debugger-protocol-viewer/tot/Target/

  1. when devtools first connects to node it probably will issue Target.setAutoAttach: image
  2. You won't do anything with that, but it's nice of devtools to say it'll talk to your children. :)
  3. Soon after you announce the creation of the primary child_process via a Target.targetCreated event: image
  4. Later when you launch your forked inspect children, you will inform devtools of them with the Target.attachedToTarget event: image
  5. The event params is TargetInfo. I believe the ID can be whatever you want, but the type should be "node". BTW here's some of how that type is handled in the devtools source. (also this)
  6. Then the devtools will be sending messages for your children via Target. sendMessageToTarget and you'll want to pass it along.
  7. You can respond with messages from the children to devtools with theTarget.receivedMessageFromTarget event.

Doing that should get you this sweet UI and everything else just comes totally free.


I probably left out details around how you announce the death of child_processes, etc.. but it's something else here in the Target domain.
FYI: To understand this better myself, I inspected the devtools protocol (over websocket). This is pretty straightforward... see "Sniffing the protocol" on https://developer.chrome.com/devtools/docs/debugger-protocol#sniffing-the protocol

really happy ya'll are taking this on. excited. :)

@paulirish - Thank you!

My current communication with devtools is an incredibly naive approach that utilizes selenium to drive the UI (at best its a brittle hack). I'm going to have to do a deep dive into the information you sent over, but I'm encouraged by possibilities.

Shoulnd't 👿-lementation of child process debugging be in node?

@mightyiam perhaps. At this point, this sort of work would almost be easier to do in node-core as then inspect-process wouldn't have to get into the business of becoming a websocket MITM proxy for the protocol.

It might be a tad easier to prototype the work over here and then once its proven, upstream it to node-core. shrug

@jaridmargolin i just looked and you're just using selenium to manage the devtools window. all that stuff could stay the same.. it's just that the debuggerUrl that gets opened, would be adjusted to be opening your new websocket endpoint rather than node's.

A quick note, following on from #37 (comment)

I have the following npm script:

"start:debug": "nodemon -w src src/index.js --exec 'babel-node --inspect=1234'"

This allows me to:

  • debug/step through ES6 sourcemaps rather than transpiled code (using babel-node)
  • watch for changes (using nodemon)
  • specify a debug port (with --inspect=1234)

If the resolution to this issue allows the above script to be wrapped by inspect-process, then can I suggest it's added to the docs as an example?

I am unable to connect with chrome to debug my node app, that is running in mine docker.

This is my command:

"dev": "nodemon -w src --exec 'babel-node --inspect=1234 src --presets es2015,stage-2'"

And this is my docker-compose.yml

version: '3'
 express:
    build: .
    ports:
     - 3001:3000
     - 1234:1234

This is the log:

Debugger listening on ws://127.0.0.1:1234/61dd50d6-3190-445a-9316-79383758aced
express_1  | For help see https://nodejs.org/en/docs/inspector
express_1  | 17 Jul 02:49:30 - Listening on port 3000

I configure 127.0.0.1:1234 in chrome://inspect/#devices

What am I doing wrong?

inspect-process does not currently support node 8.X. Please see #52 for progress.

  • Actually, viewing your dev command, you are not even utilizing this library :) I would advise reaching out for help on stackoverflow or a similar platform if you are looking for guidance.