探测模式


🌐 Probe mode

稳定性: 1 - 实验性

node inspect 支持通过标志 --probe 以非交互式探测模式检查应用中的运行时值。探测模式会启动应用,设置一个或多个源断点,每当触发匹配的断点时评估一个表达式,并在会话结束时(无论是正常完成还是超时)打印最终报告。这使开发者能够执行类似 printf 式的调试,而无需修改应用代码并在之后进行清理,同时它还支持用于工具的结构化输出。

$ node inspect [--json] [--preview] [--timeout=<ms>] [--port=<port>] \
    --probe app.js:10 --expr 'x' \
    [--probe app.js:20 --expr 'y' ...] \
    [--] [<node-option> ...] <script.js> [args...] 
  • --probe <file>:<line>[:<col>]:要探查的源位置。行号和列号从 1 开始。
  • --timeout=<ms>:整个探测会话的全局实时时钟截止时间。默认值为 30000。这可以用来探测可以被外部终止的长时间运行的应用。
  • --json:如果使用,将打印结构化的 JSON 报告,而不是默认的文本报告。
  • --preview:如果使用,非原始值将包括对象类 JSON 探针值的 CDP 属性预览。
  • --port=<port>:选择用于 --inspect-brk 启动路径的本地检查器端口。探测模式默认为 0,它会请求一个随机端口。
  • -- 是可选的,除非子级需要它自己专用的 Node.js 标志。

--probe--expr 参数的附加规则:

🌐 Additional rules about the --probe and --expr arguments:

  • --probe <file>:<line>[:<col>]--expr <expr> 是严格配对的。每个 --probe 必须紧跟着正好一个 --expr
  • --timeout--json--preview--port 是整个探测会话的全局探测选项。它们可以出现在探测对之前或之间,但不能出现在 --probe 与其匹配的 --expr 之间。

如果单个探针需要评估多个值,请评估 --expr 中的结构化值,例如 --expr "{ foo, bar }"--expr "[foo, bar]",并使用 --preview 在输出中包含任何类似对象的值的属性预览。

🌐 If a single probe needs to evaluate more than one value, evaluate a structured value in --expr, for example --expr "{ foo, bar }" or --expr "[foo, bar]", and use --preview to include property previews for any object-like values in the output.

探测模式仅将最终探测报告打印到标准输出,并且在其他情况下会静音子进程的标准输出/标准错误。如果子进程在探测会话开始后以错误退出,最终报告会记录一个带有退出代码和捕获的子进程标准错误的终端 error 事件。无效参数以及严重的启动或连接失败仍可能在没有最终探测结果的情况下将诊断信息打印到标准错误。

🌐 Probe mode only prints the final probe report to stdout, and otherwise silences stdout/stderr from the child process. If the child exits with an error after the probe session starts, the final report records a terminal error event with the exit code and captured child stderr. Invalid arguments and fatal launch or connect failures may still print diagnostics to stderr without a final probe result.

考虑这个脚本:

🌐 Consider this script:

// cli.js
let maxRSS = 0;
for (let i = 0; i < 2; i++) {
  const { rss } = process.memoryUsage();
  maxRSS = Math.max(maxRSS, rss);
} 

如果未使用 --json,输出将以人类可读的文本格式打印:

🌐 If --json is not used, the output is printed in a human-readable text format:

$ node inspect --probe cli.js:5 --expr 'rss' cli.js
Hit 1 at cli.js:5
  rss = 54935552
Hit 2 at cli.js:5
  rss = 55083008
Completed 

原始结果会直接打印,而对象和数组在可用时会使用 Chrome 开发者工具协议预览数据。其他非原始值会回退到 Chrome 开发者工具协议 description 字符串。表达式失败会记录为 [error] ... 行,并且不会导致整体会话失败。如果需要更丰富的文本格式,可以将表达式封装在 JSON.stringify(...)util.inspect(...) 中。

🌐 Primitive results are printed directly, while objects and arrays use Chrome DevTools Protocol preview data when available. Other non-primitive values fall back to the Chrome DevTools Protocol description string. Expression failures are recorded as [error] ... lines and do not fail the overall session. If richer text formatting is needed, wrap the expression in JSON.stringify(...) or util.inspect(...).

当使用 --json 时,输出形状如下:

🌐 When --json is used, the output shape looks like this:

$ node inspect --json --probe cli.js:5 --expr 'rss' cli.js
{"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"}]} 
{
  "v": 1, // Probe JSON schema version.
  "probes": [
    {
      "expr": "rss", // The expression paired with --probe.
      "target": ["cli.js", 5] // [file, line] or [file, line, col].
    }
  ],
  "results": [
    {
      "probe": 0, // Index into probes[].
      "event": "hit", // Hit events are recorded in observation order.
      "hit": 1, // 1-based hit count for this probe.
      "result": {
        "type": "number",
        "value": 55443456,
        "description": "55443456"
      }
      // If the expression throws, "error" is present instead of "result".
    },
    {
      "probe": 0,
      "event": "hit",
      "hit": 2,
      "result": {
        "type": "number",
        "value": 55574528,
        "description": "55574528"
      }
    },
    {
      "event": "completed"
      // The final entry is always a terminal event, for example:
      // 1. { "event": "completed" }
      // 2. { "event": "miss", "pending": [0, 1] }
      // 3. {
      //      "event": "timeout",
      //      "pending": [0],
      //      "error": {
      //       "code": "probe_timeout",
      //       "message": "Timed out after 30000ms waiting for probes: app.js:10"
      //      }
      //    }
      // 4. {
      //      "event": "error",
      //      "pending": [0],
      //      "error": {
      //       "code": "probe_target_exit",
      //       "exitCode": 1,
      //       "stderr": "[Error: boom]",
      //       "message": "Target exited with code 1 before probes: app.js:10"
      //      }
      //    }
    }
  ]
}