@@ -90,6 +90,157 @@ steps to the next line. Type `help` to see what other commands are available. |
90 | 90 | Pressing `enter` without typing a command will repeat the previous debugger |
91 | 91 | command. |
92 | 92 |
|
| 93 | +## 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 | + |
93 | 244 | ## Watchers |
94 | 245 |
|
95 | 246 | It is possible to watch expression and variable values while debugging. On |
|