◐ Shell
clean mode source ↗

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.

9090

Pressing `enter` without typing a command will repeat the previous debugger

9191

command.

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

9424595246

It is possible to watch expression and variable values while debugging. On