Skip to content

Commit 8cb1312

Browse files
cola119marco-ippolito
authored andcommittedJun 17, 2024
inspector: introduce the --inspect-wait flag
PR-URL: #52734 Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
1 parent 4102244 commit 8cb1312

File tree

7 files changed

+90
-10
lines changed

7 files changed

+90
-10
lines changed
 

‎doc/api/cli.md

+16
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,7 @@ Activate inspector on `host:port`. Default is `127.0.0.1:9229`.
11961196
V8 inspector integration allows tools such as Chrome DevTools and IDEs to debug
11971197
and profile Node.js instances. The tools attach to Node.js instances via a
11981198
tcp port and communicate using the [Chrome DevTools Protocol][].
1199+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
11991200

12001201
<!-- Anchor to make sure old links find a target -->
12011202

@@ -1226,6 +1227,8 @@ added: v7.6.0
12261227
Activate inspector on `host:port` and break at start of user script.
12271228
Default `host:port` is `127.0.0.1:9229`.
12281229

1230+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
1231+
12291232
### `--inspect-port=[host:]port`
12301233

12311234
<!-- YAML
@@ -1247,6 +1250,17 @@ Specify ways of the inspector web socket url exposure.
12471250
By default inspector websocket url is available in stderr and under `/json/list`
12481251
endpoint on `http://host:port/json/list`.
12491252

1253+
### `--inspect-wait[=[host:]port]`
1254+
1255+
<!-- YAML
1256+
added: REPLACEME
1257+
-->
1258+
1259+
Activate inspector on `host:port` and wait for debugger to be attached.
1260+
Default `host:port` is `127.0.0.1:9229`.
1261+
1262+
See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger.
1263+
12501264
### `-i`, `--interactive`
12511265

12521266
<!-- YAML
@@ -2520,6 +2534,7 @@ one is included in the list below.
25202534
* `--inspect-brk`
25212535
* `--inspect-port`, `--debug-port`
25222536
* `--inspect-publish-uid`
2537+
* `--inspect-wait`
25232538
* `--inspect`
25242539
* `--max-http-header-size`
25252540
* `--napi-modules`
@@ -2971,6 +2986,7 @@ done
29712986
[ShadowRealm]: https://github.com/tc39/proposal-shadowrealm
29722987
[Source Map]: https://sourcemaps.info/spec.html
29732988
[Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
2989+
[V8 Inspector integration for Node.js]: debugger.md#v8-inspector-integration-for-nodejs
29742990
[V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html
29752991
[Web Crypto API]: webcrypto.md
29762992
[`"type"`]: packages.md#type

‎doc/api/debugger.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,21 @@ V8 Inspector can be enabled by passing the `--inspect` flag when starting a
234234
Node.js application. It is also possible to supply a custom port with that flag,
235235
e.g. `--inspect=9222` will accept DevTools connections on port 9222.
236236

237-
To break on the first line of the application code, pass the `--inspect-brk`
238-
flag instead of `--inspect`.
237+
Using the `--inspect` flag will execute the code immediately before debugger is connected.
238+
This means that the code will start running before you can start debugging, which might
239+
not be ideal if you want to debug from the very beginning.
240+
241+
In such cases, you have two alternatives:
242+
243+
1. `--inspect-wait` flag: This flag will wait for debugger to be attached before executing the code.
244+
This allows you to start debugging right from the beginning of the execution.
245+
2. `--inspect-brk` flag: Unlike `--inspect`, this flag will break on the first line of the code
246+
as soon as debugger is attached. This is useful when you want to debug the code step by step
247+
from the very beginning, without any code execution prior to debugging.
248+
249+
So, when deciding between `--inspect`, `--inspect-wait`, and `--inspect-brk`, consider whether you want
250+
the code to start executing immediately, wait for debugger to be attached before execution,
251+
or break on the first line for step-by-step debugging.
239252

240253
```console
241254
$ node --inspect index.js

‎doc/node.1

+5
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,11 @@ and
282282
Default is
283283
.Sy stderr,http .
284284
.
285+
.It Fl -inspect-wait Ns = Ns Ar [host:]port
286+
Activate inspector on
287+
.Ar host:port
288+
and wait for debugger to be attached.
289+
.
285290
.It Fl -inspect Ns = Ns Ar [host:]port
286291
Activate inspector on
287292
.Ar host:port .

‎src/inspector_agent.cc

+12-8
Original file line numberDiff line numberDiff line change
@@ -743,20 +743,24 @@ bool Agent::Start(const std::string& path,
743743
}, parent_env_);
744744

745745
bool wait_for_connect = options.wait_for_connect();
746+
bool should_break_first_line = options.should_break_first_line();
746747
if (parent_handle_) {
747-
wait_for_connect = parent_handle_->WaitForConnect();
748-
parent_handle_->WorkerStarted(client_->getThreadHandle(), wait_for_connect);
748+
should_break_first_line = parent_handle_->WaitForConnect();
749+
parent_handle_->WorkerStarted(client_->getThreadHandle(),
750+
should_break_first_line);
749751
} else if (!options.inspector_enabled || !options.allow_attaching_debugger ||
750752
!StartIoThread()) {
751753
return false;
752754
}
753755

754-
// Patch the debug options to implement waitForDebuggerOnStart for
755-
// the NodeWorker.enable method.
756-
if (wait_for_connect) {
757-
CHECK(!parent_env_->has_serialized_options());
758-
debug_options_.EnableBreakFirstLine();
759-
parent_env_->options()->get_debug_options()->EnableBreakFirstLine();
756+
if (wait_for_connect || should_break_first_line) {
757+
// Patch the debug options to implement waitForDebuggerOnStart for
758+
// the NodeWorker.enable method.
759+
if (should_break_first_line) {
760+
CHECK(!parent_env_->has_serialized_options());
761+
debug_options_.EnableBreakFirstLine();
762+
parent_env_->options()->get_debug_options()->EnableBreakFirstLine();
763+
}
760764
client_->waitForFrontend();
761765
}
762766
return true;

‎src/node_options.cc

+8
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,14 @@ DebugOptionsParser::DebugOptionsParser() {
337337
Implies("--inspect-brk-node", "--inspect");
338338
AddAlias("--inspect-brk-node=", { "--inspect-port", "--inspect-brk-node" });
339339

340+
AddOption(
341+
"--inspect-wait",
342+
"activate inspector on host:port and wait for debugger to be attached",
343+
&DebugOptions::inspect_wait,
344+
kAllowedInEnvvar);
345+
Implies("--inspect-wait", "--inspect");
346+
AddAlias("--inspect-wait=", {"--inspect-port", "--inspect-wait"});
347+
340348
AddOption("--inspect-publish-uid",
341349
"comma separated list of destinations for inspector uid"
342350
"(default: stderr,http)",

‎src/node_options.h

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class DebugOptions : public Options {
7171
bool allow_attaching_debugger = true;
7272
// --inspect
7373
bool inspector_enabled = false;
74+
// --inspect-wait
75+
bool inspect_wait = false;
7476
// --debug
7577
bool deprecated_debug = false;
7678
// --inspect-brk
@@ -93,6 +95,10 @@ class DebugOptions : public Options {
9395
}
9496

9597
bool wait_for_connect() const {
98+
return break_first_line || break_node_first_line || inspect_wait;
99+
}
100+
101+
bool should_break_first_line() const {
96102
return break_first_line || break_node_first_line;
97103
}
98104

‎test/parallel/test-inspector-wait.mjs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as common from '../common/index.mjs';
2+
3+
common.skipIfInspectorDisabled();
4+
5+
import assert from 'node:assert';
6+
import { NodeInstance } from '../common/inspector-helper.js';
7+
8+
9+
async function runTests() {
10+
const child = new NodeInstance(['--inspect-wait=0'], 'console.log(0);');
11+
const session = await child.connectInspectorSession();
12+
await session.send({ method: 'NodeRuntime.enable' });
13+
await session.waitForNotification('NodeRuntime.waitingForDebugger');
14+
15+
// The execution should be paused until the debugger is attached
16+
while (await child.nextStderrString() !== 'Debugger attached.');
17+
18+
await session.send({ 'method': 'Runtime.runIfWaitingForDebugger' });
19+
20+
// Wait for the execution to finish
21+
while (await child.nextStderrString() !== 'Waiting for the debugger to disconnect...');
22+
23+
await session.send({ method: 'NodeRuntime.disable' });
24+
session.disconnect();
25+
assert.strictEqual((await child.expectShutdown()).exitCode, 0);
26+
}
27+
28+
runTests().then(common.mustCall());

0 commit comments

Comments
 (0)
Please sign in to comment.