debugger: add edit-free runtime expression probes to `node inspect` · nodejs/node@ec2451b
@@ -90,6 +90,157 @@ steps to the next line. Type `help` to see what other commands are available.
9090Pressing `enter` without typing a command will repeat the previous debugger
9191command.
929293+## Probe mode
94+95+<!-- YAML
96+added:
97+ - REPLACEME
98+-->
99+100+> Stability: 1 - Experimental
101+102+`node inspect` supports a non-interactive probe mode for inspecting runtime values
103+in an application via the flag `--probe`. Probe mode launches the application,
104+sets one or more source breakpoints, evaluates one expression whenever a
105+matching breakpoint is hit, and prints one final report when the session ends
106+(either on normal completion or timeout). This allows developers to perform
107+printf-style debugging without having to modify the application code and
108+clean up afterwards, and it supports structured output for tool use.
109+110+```console
111+$ node inspect [--json] [--preview] [--timeout=<ms>] [--port=<port>] \
112+ --probe app.js:10 --expr 'x' \
113+ [--probe app.js:20 --expr 'y' ...] \
114+ [--] [<node-option> ...] <script.js> [args...]
115+```
116+117+* `--probe <file>:<line>[:<col>]`: Source location to probe. Line and column number
118+ are 1-based.
119+* `--timeout=<ms>`: A global wall-clock deadline for the entire probe session.
120+ The default is `30000`. This can be used to probe a long-running application
121+ that can be terminated externally.
122+* `--json`: If used, prints a structured JSON report instead of the default text report.
123+* `--preview`: If used, non-primitive values will include CDP property previews for
124+ object-like JSON probe values.
125+* `--port=<port>`: Selects the local inspector port used for the `--inspect-brk`
126+ launch path. Probe mode defaults to `0`, which requests a random port.
127+* `--` is optional unless the child needs its own Node.js flags.
128+129+Additional rules about the `--probe` and `--expr` arguments:
130+131+* `--probe <file>:<line>[:<col>]` and `--expr <expr>` are strict pairs. Each
132+`--probe` must be followed immediately by exactly one `--expr`.
133+* `--timeout`, `--json`, `--preview`, and `--port` are global probe options
134+ for the whole probe session. They may appear before or between probe pairs,
135+ but not between a `--probe` and its matching `--expr`.
136+137+If a single probe needs to evaluate more than one value,
138+evaluate a structured value in `--expr`, for example `--expr "{ foo, bar }"`
139+or `--expr "[foo, bar]"`, and use `--preview` to include property previews for
140+any object-like values in the output.
141+142+Probe mode only prints the final probe report to stdout, and otherwise silences
143+stdout/stderr from the child process. If the child exits with an error after the
144+probe session starts, the final report records a terminal `error` event with the
145+exit code and captured child stderr. Invalid arguments and fatal launch or
146+connect failures may still print diagnostics to stderr without a final probe
147+result.
148+149+Consider this script:
150+151+```js
152+// cli.js
153+let maxRSS = 0;
154+for (let i = 0; i < 2; i++) {
155+const { rss } = process.memoryUsage();
156+ maxRSS = Math.max(maxRSS, rss);
157+}
158+```
159+160+If `--json` is not used, the output is printed in a human-readable text format:
161+162+```console
163+$ node inspect --probe cli.js:5 --expr 'rss' cli.js
164+Hit 1 at cli.js:5
165+ rss = 54935552
166+Hit 2 at cli.js:5
167+ rss = 55083008
168+Completed
169+```
170+171+Primitive results are printed directly, while objects and arrays use Chrome
172+DevTools Protocol preview data when available. Other non-primitive values
173+fall back to the Chrome DevTools Protocol `description` string.
174+Expression failures are recorded as `[error] ...` lines and do not fail
175+the overall session. If richer text formatting is needed, wrap the expression
176+in `JSON.stringify(...)` or `util.inspect(...)`.
177+178+When `--json` is used, the output shape looks like this:
179+180+```console
181+$ node inspect --json --probe cli.js:5 --expr 'rss' cli.js
182+{"v":1,"probes":[{"expr":"rss","target":["cli.js",5]}],"results":[{"probe":0,"event":"hit","hit":1,"result":{"type":"number","value":55443456,"description":"55443456"}},{"probe":0,"event":"hit","hit":2,"result":{"type":"number","value":55574528,"description":"55574528"}},{"event":"completed"}]}
183+```
184+185+```json
186+{
187+"v": 1, // Probe JSON schema version.
188+"probes": [
189+ {
190+"expr": "rss", // The expression paired with --probe.
191+"target": ["cli.js", 5] // [file, line] or [file, line, col].
192+ }
193+ ],
194+"results": [
195+ {
196+"probe": 0, // Index into probes[].
197+"event": "hit", // Hit events are recorded in observation order.
198+"hit": 1, // 1-based hit count for this probe.
199+"result": {
200+"type": "number",
201+"value": 55443456,
202+"description": "55443456"
203+ }
204+// If the expression throws, "error" is present instead of "result".
205+ },
206+ {
207+"probe": 0,
208+"event": "hit",
209+"hit": 2,
210+"result": {
211+"type": "number",
212+"value": 55574528,
213+"description": "55574528"
214+ }
215+ },
216+ {
217+"event": "completed"
218+// The final entry is always a terminal event, for example:
219+// 1. { "event": "completed" }
220+// 2. { "event": "miss", "pending": [0, 1] }
221+// 3. {
222+// "event": "timeout",
223+// "pending": [0],
224+// "error": {
225+// "code": "probe_timeout",
226+// "message": "Timed out after 30000ms waiting for probes: app.js:10"
227+// }
228+// }
229+// 4. {
230+// "event": "error",
231+// "pending": [0],
232+// "error": {
233+// "code": "probe_target_exit",
234+// "exitCode": 1,
235+// "stderr": "[Error: boom]",
236+// "message": "Target exited with code 1 before probes: app.js:10"
237+// }
238+// }
239+}
240+]
241+}
242+```
243+93244## Watchers
9424595246It is possible to watch expression and variable values while debugging. On