Node.js v20.11.1 文档


诊断报告#

¥Diagnostic report

稳定性: 2 - 稳定的

¥Stability: 2 - Stable

提供 JSON 格式的诊断摘要,写入文件。

¥Delivers a JSON-formatted diagnostic summary, written to a file.

该报告旨在供开发、测试和生产使用,以捕获和保存信息以用于问题确定。它包括 JavaScript 和原生堆栈跟踪、堆统计信息、平台信息、资源使用情况等。启用报告选项后,除了通过 API 调用以编程方式触发之外,还可以针对未处理的异常、致命错误和用户信号触发诊断报告。

¥The report is intended for development, test, and production use, to capture and preserve information for problem determination. It includes JavaScript and native stack traces, heap statistics, platform information, resource usage etc. With the report option enabled, diagnostic reports can be triggered on unhandled exceptions, fatal errors and user signals, in addition to triggering programmatically through API calls.

下面提供了针对未捕获异常生成的完整示例报告以供参考。

¥A complete example report that was generated on an uncaught exception is provided below for reference.

{
  "header": {
    "reportVersion": 3,
    "event": "exception",
    "trigger": "Exception",
    "filename": "report.20181221.005011.8974.0.001.json",
    "dumpEventTime": "2018-12-21T00:50:11Z",
    "dumpEventTimeStamp": "1545371411331",
    "processId": 8974,
    "cwd": "/home/nodeuser/project/node",
    "commandLine": [
      "/home/nodeuser/project/node/out/Release/node",
      "--report-uncaught-exception",
      "/home/nodeuser/project/node/test/report/test-exception.js",
      "child"
    ],
    "nodejsVersion": "v12.0.0-pre",
    "glibcVersionRuntime": "2.17",
    "glibcVersionCompiler": "2.17",
    "wordSize": "64 bit",
    "arch": "x64",
    "platform": "linux",
    "componentVersions": {
      "node": "12.0.0-pre",
      "v8": "7.1.302.28-node.5",
      "uv": "1.24.1",
      "zlib": "1.2.11",
      "ares": "1.15.0",
      "modules": "68",
      "nghttp2": "1.34.0",
      "napi": "3",
      "llhttp": "1.0.1",
      "openssl": "1.1.0j"
    },
    "release": {
      "name": "node"
    },
    "osName": "Linux",
    "osRelease": "3.10.0-862.el7.x86_64",
    "osVersion": "#1 SMP Wed Mar 21 18:14:51 EDT 2018",
    "osMachine": "x86_64",
    "cpus": [
      {
        "model": "Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz",
        "speed": 2700,
        "user": 88902660,
        "nice": 0,
        "sys": 50902570,
        "idle": 241732220,
        "irq": 0
      },
      {
        "model": "Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz",
        "speed": 2700,
        "user": 88902660,
        "nice": 0,
        "sys": 50902570,
        "idle": 241732220,
        "irq": 0
      }
    ],
    "networkInterfaces": [
      {
        "name": "en0",
        "internal": false,
        "mac": "13:10:de:ad:be:ef",
        "address": "10.0.0.37",
        "netmask": "255.255.255.0",
        "family": "IPv4"
      }
    ],
    "host": "test_machine"
  },
  "javascriptStack": {
    "message": "Error: *** test-exception.js: throwing uncaught Error",
    "stack": [
      "at myException (/home/nodeuser/project/node/test/report/test-exception.js:9:11)",
      "at Object.<anonymous> (/home/nodeuser/project/node/test/report/test-exception.js:12:3)",
      "at Module._compile (internal/modules/cjs/loader.js:718:30)",
      "at Object.Module._extensions..js (internal/modules/cjs/loader.js:729:10)",
      "at Module.load (internal/modules/cjs/loader.js:617:32)",
      "at tryModuleLoad (internal/modules/cjs/loader.js:560:12)",
      "at Function.Module._load (internal/modules/cjs/loader.js:552:3)",
      "at Function.Module.runMain (internal/modules/cjs/loader.js:771:12)",
      "at executeUserCode (internal/bootstrap/node.js:332:15)"
    ]
  },
  "nativeStack": [
    {
      "pc": "0x000055b57f07a9ef",
      "symbol": "report::GetNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, v8::Local<v8::String>, std::ostream&) [./node]"
    },
    {
      "pc": "0x000055b57f07cf03",
      "symbol": "report::GetReport(v8::FunctionCallbackInfo<v8::Value> const&) [./node]"
    },
    {
      "pc": "0x000055b57f1bccfd",
      "symbol": " [./node]"
    },
    {
      "pc": "0x000055b57f1be048",
      "symbol": "v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [./node]"
    },
    {
      "pc": "0x000055b57feeda0e",
      "symbol": " [./node]"
    }
  ],
  "javascriptHeap": {
    "totalMemory": 5660672,
    "executableMemory": 524288,
    "totalCommittedMemory": 5488640,
    "availableMemory": 4341379928,
    "totalGlobalHandlesMemory": 8192,
    "usedGlobalHandlesMemory": 3136,
    "usedMemory": 4816432,
    "memoryLimit": 4345298944,
    "mallocedMemory": 254128,
    "externalMemory": 315644,
    "peakMallocedMemory": 98752,
    "nativeContextCount": 1,
    "detachedContextCount": 0,
    "doesZapGarbage": 0,
    "heapSpaces": {
      "read_only_space": {
        "memorySize": 524288,
        "committedMemory": 39208,
        "capacity": 515584,
        "used": 30504,
        "available": 485080
      },
      "new_space": {
        "memorySize": 2097152,
        "committedMemory": 2019312,
        "capacity": 1031168,
        "used": 985496,
        "available": 45672
      },
      "old_space": {
        "memorySize": 2273280,
        "committedMemory": 1769008,
        "capacity": 1974640,
        "used": 1725488,
        "available": 249152
      },
      "code_space": {
        "memorySize": 696320,
        "committedMemory": 184896,
        "capacity": 152128,
        "used": 152128,
        "available": 0
      },
      "map_space": {
        "memorySize": 536576,
        "committedMemory": 344928,
        "capacity": 327520,
        "used": 327520,
        "available": 0
      },
      "large_object_space": {
        "memorySize": 0,
        "committedMemory": 0,
        "capacity": 1520590336,
        "used": 0,
        "available": 1520590336
      },
      "new_large_object_space": {
        "memorySize": 0,
        "committedMemory": 0,
        "capacity": 0,
        "used": 0,
        "available": 0
      }
    }
  },
  "resourceUsage": {
    "rss": "35766272",
    "free_memory": "1598337024",
    "total_memory": "17179869184",
    "available_memory": "1598337024",
    "maxRss": "36624662528",
    "constrained_memory": "36624662528",
    "userCpuSeconds": 0.040072,
    "kernelCpuSeconds": 0.016029,
    "cpuConsumptionPercent": 5.6101,
    "userCpuConsumptionPercent": 4.0072,
    "kernelCpuConsumptionPercent": 1.6029,
    "pageFaults": {
      "IORequired": 0,
      "IONotRequired": 4610
    },
    "fsActivity": {
      "reads": 0,
      "writes": 0
    }
  },
  "uvthreadResourceUsage": {
    "userCpuSeconds": 0.039843,
    "kernelCpuSeconds": 0.015937,
    "cpuConsumptionPercent": 5.578,
    "userCpuConsumptionPercent": 3.9843,
    "kernelCpuConsumptionPercent": 1.5937,
    "fsActivity": {
      "reads": 0,
      "writes": 0
    }
  },
  "libuv": [
    {
      "type": "async",
      "is_active": true,
      "is_referenced": false,
      "address": "0x0000000102910900",
      "details": ""
    },
    {
      "type": "timer",
      "is_active": false,
      "is_referenced": false,
      "address": "0x00007fff5fbfeab0",
      "repeat": 0,
      "firesInMsFromNow": 94403548320796,
      "expired": true
    },
    {
      "type": "check",
      "is_active": true,
      "is_referenced": false,
      "address": "0x00007fff5fbfeb48"
    },
    {
      "type": "idle",
      "is_active": false,
      "is_referenced": true,
      "address": "0x00007fff5fbfebc0"
    },
    {
      "type": "prepare",
      "is_active": false,
      "is_referenced": false,
      "address": "0x00007fff5fbfec38"
    },
    {
      "type": "check",
      "is_active": false,
      "is_referenced": false,
      "address": "0x00007fff5fbfecb0"
    },
    {
      "type": "async",
      "is_active": true,
      "is_referenced": false,
      "address": "0x000000010188f2e0"
    },
    {
      "type": "tty",
      "is_active": false,
      "is_referenced": true,
      "address": "0x000055b581db0e18",
      "width": 204,
      "height": 55,
      "fd": 17,
      "writeQueueSize": 0,
      "readable": true,
      "writable": true
    },
    {
      "type": "signal",
      "is_active": true,
      "is_referenced": false,
      "address": "0x000055b581d80010",
      "signum": 28,
      "signal": "SIGWINCH"
    },
    {
      "type": "tty",
      "is_active": true,
      "is_referenced": true,
      "address": "0x000055b581df59f8",
      "width": 204,
      "height": 55,
      "fd": 19,
      "writeQueueSize": 0,
      "readable": true,
      "writable": true
    },
    {
      "type": "loop",
      "is_active": true,
      "address": "0x000055fc7b2cb180",
      "loopIdleTimeSeconds": 22644.8
    }
  ],
  "workers": [],
  "environmentVariables": {
    "REMOTEHOST": "REMOVED",
    "MANPATH": "/opt/rh/devtoolset-3/root/usr/share/man:",
    "XDG_SESSION_ID": "66126",
    "HOSTNAME": "test_machine",
    "HOST": "test_machine",
    "TERM": "xterm-256color",
    "SHELL": "/bin/csh",
    "SSH_CLIENT": "REMOVED",
    "PERL5LIB": "/opt/rh/devtoolset-3/root//usr/lib64/perl5/vendor_perl:/opt/rh/devtoolset-3/root/usr/lib/perl5:/opt/rh/devtoolset-3/root//usr/share/perl5/vendor_perl",
    "OLDPWD": "/home/nodeuser/project/node/src",
    "JAVACONFDIRS": "/opt/rh/devtoolset-3/root/etc/java:/etc/java",
    "SSH_TTY": "/dev/pts/0",
    "PCP_DIR": "/opt/rh/devtoolset-3/root",
    "GROUP": "normaluser",
    "USER": "nodeuser",
    "LD_LIBRARY_PATH": "/opt/rh/devtoolset-3/root/usr/lib64:/opt/rh/devtoolset-3/root/usr/lib",
    "HOSTTYPE": "x86_64-linux",
    "XDG_CONFIG_DIRS": "/opt/rh/devtoolset-3/root/etc/xdg:/etc/xdg",
    "MAIL": "/var/spool/mail/nodeuser",
    "PATH": "/home/nodeuser/project/node:/opt/rh/devtoolset-3/root/usr/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin",
    "PWD": "/home/nodeuser/project/node",
    "LANG": "en_US.UTF-8",
    "PS1": "\\u@\\h : \\[\\e[31m\\]\\w\\[\\e[m\\] >  ",
    "SHLVL": "2",
    "HOME": "/home/nodeuser",
    "OSTYPE": "linux",
    "VENDOR": "unknown",
    "PYTHONPATH": "/opt/rh/devtoolset-3/root/usr/lib64/python2.7/site-packages:/opt/rh/devtoolset-3/root/usr/lib/python2.7/site-packages",
    "MACHTYPE": "x86_64",
    "LOGNAME": "nodeuser",
    "XDG_DATA_DIRS": "/opt/rh/devtoolset-3/root/usr/share:/usr/local/share:/usr/share",
    "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
    "INFOPATH": "/opt/rh/devtoolset-3/root/usr/share/info",
    "XDG_RUNTIME_DIR": "/run/user/50141",
    "_": "./node"
  },
  "userLimits": {
    "core_file_size_blocks": {
      "soft": "",
      "hard": "unlimited"
    },
    "data_seg_size_kbytes": {
      "soft": "unlimited",
      "hard": "unlimited"
    },
    "file_size_blocks": {
      "soft": "unlimited",
      "hard": "unlimited"
    },
    "max_locked_memory_bytes": {
      "soft": "unlimited",
      "hard": 65536
    },
    "max_memory_size_kbytes": {
      "soft": "unlimited",
      "hard": "unlimited"
    },
    "open_files": {
      "soft": "unlimited",
      "hard": 4096
    },
    "stack_size_bytes": {
      "soft": "unlimited",
      "hard": "unlimited"
    },
    "cpu_time_seconds": {
      "soft": "unlimited",
      "hard": "unlimited"
    },
    "max_user_processes": {
      "soft": "unlimited",
      "hard": 4127290
    },
    "virtual_memory_kbytes": {
      "soft": "unlimited",
      "hard": "unlimited"
    }
  },
  "sharedObjects": [
    "/lib64/libdl.so.2",
    "/lib64/librt.so.1",
    "/lib64/libstdc++.so.6",
    "/lib64/libm.so.6",
    "/lib64/libgcc_s.so.1",
    "/lib64/libpthread.so.0",
    "/lib64/libc.so.6",
    "/lib64/ld-linux-x86-64.so.2"
  ]
} 

使用方法#

¥Usage

node --report-uncaught-exception --report-on-signal \
--report-on-fatalerror app.js 
  • --report-uncaught-exception 允许生成关于未捕获异常的报告。当结合原生堆栈和其他运行时环境数据检查 JavaScript 堆栈时很有用。

    ¥--report-uncaught-exception Enables report to be generated on un-caught exceptions. Useful when inspecting JavaScript stack in conjunction with native stack and other runtime environment data.

  • --report-on-signal 在接收到正在运行的 Node.js 进程的指定(或预定义)信号时生成报告。(请参阅下文了解如何修改触发报告的信号。)默认信号为 SIGUSR2。当需要从另一个程序触发报告时很有用。应用监视器可以利用此特性定期收集报告并将丰富的内部运行时数据集绘制到其视图中。

    ¥--report-on-signal Enables report to be generated upon receiving the specified (or predefined) signal to the running Node.js process. (See below on how to modify the signal that triggers the report.) Default signal is SIGUSR2. Useful when a report needs to be triggered from another program. Application monitors may leverage this feature to collect report at regular intervals and plot rich set of internal runtime data to their views.

Windows 不支持基于信号的报告生成。

¥Signal based report generation is not supported in Windows.

一般情况下,不需要修改上报触发信号。然而,如果 SIGUSR2 已经被用于其他目的,则此标志有助于改变报告生成的信号,并为上述目的保留 SIGUSR2 的原始含义。

¥Under normal circumstances, there is no need to modify the report triggering signal. However, if SIGUSR2 is already used for other purposes, then this flag helps to change the signal for report generation and preserve the original meaning of SIGUSR2 for the said purposes.

  • --report-on-fatalerror 允许在导致应用终止的致命错误(Node.js 运行时内的内部错误,例如内存不足)时触发报告。有助于检查各种诊断数据元素,如堆、堆栈、事件循环状态、资源消耗等,以推断致命错误。

    ¥--report-on-fatalerror Enables the report to be triggered on fatal errors (internal errors within the Node.js runtime, such as out of memory) that leads to termination of the application. Useful to inspect various diagnostic data elements such as heap, stack, event loop state, resource consumption etc. to reason about the fatal error.

  • --report-compact 以紧凑的单行 JSON 格式编写报告,与专为人类使用而设计的默认多行格式相比,日志处理系统更易于使用。

    ¥--report-compact Write reports in a compact format, single-line JSON, more easily consumable by log processing systems than the default multi-line format designed for human consumption.

  • --report-directory 生成报告的位置。

    ¥--report-directory Location at which the report will be generated.

  • --report-filename 将写入报告的文件的名称。

    ¥--report-filename Name of the file to which the report will be written.

  • --report-signal 设置或重置报告生成信号(Windows 不支持)。默认信号为 SIGUSR2

    ¥--report-signal Sets or resets the signal for report generation (not supported on Windows). Default signal is SIGUSR2.

报告也可以通过 JavaScript 应用的 API 调用触发:

¥A report can also be triggered via an API call from a JavaScript application:

process.report.writeReport(); 

此函数接受可选的额外参数 filename,其是写入报告的文件的名称。

¥This function takes an optional additional argument filename, which is the name of a file into which the report is written.

process.report.writeReport('./foo.json'); 

此函数接受可选的额外参数 err,其是 Error 对象,将用作报告中打印的 JavaScript 堆栈的上下文。当使用报告处理回调或异常句柄中的错误时,这允许报告包括原始错误的位置以及处理它的位置。

¥This function takes an optional additional argument err which is an Error object that will be used as the context for the JavaScript stack printed in the report. When using report to handle errors in a callback or an exception handler, this allows the report to include the location of the original error as well as where it was handled.

try {
  process.chdir('/non-existent-path');
} catch (err) {
  process.report.writeReport(err);
}
// Any other code 

如果文件名和错误对象都传给 writeReport(),则错误对象必须是第二个参数。

¥If both filename and error object are passed to writeReport() the error object must be the second parameter.

try {
  process.chdir('/non-existent-path');
} catch (err) {
  process.report.writeReport(filename, err);
}
// Any other code 

诊断报告的内容可以通过 JavaScript 应用的 API 调用作为 JavaScript 对象返回:

¥The content of the diagnostic report can be returned as a JavaScript Object via an API call from a JavaScript application:

const report = process.report.getReport();
console.log(typeof report === 'object'); // true

// Similar to process.report.writeReport() output
console.log(JSON.stringify(report, null, 2)); 

此函数接受可选的额外参数 err,其是 Error 对象,将用作报告中打印的 JavaScript 堆栈的上下文。

¥This function takes an optional additional argument err, which is an Error object that will be used as the context for the JavaScript stack printed in the report.

const report = process.report.getReport(new Error('custom error'));
console.log(typeof report === 'object'); // true 

API 版本在从应用内部检查运行时状态时很有用,期望自我调整资源消耗、负载平衡、监控等。

¥The API versions are useful when inspecting the runtime state from within the application, in expectation of self-adjusting the resource consumption, load balancing, monitoring etc.

报告的内容由包含事件类型、日期、时间、PID 和 Node.js 版本的标头部分、包含 JavaScript 和原生堆栈跟踪的部分、包含 V8 堆信息的部分、包含 libuv 句柄信息的部分和显示 CPU 和内存使用情况以及系统限制的操作系统平台信息部分。可以使用 Node.js 交互式解释器触发的示例报告:

¥The content of the report consists of a header section containing the event type, date, time, PID, and Node.js version, sections containing JavaScript and native stack traces, a section containing V8 heap information, a section containing libuv handle information, and an OS platform information section showing CPU and memory usage and system limits. An example report can be triggered using the Node.js REPL:

$ node
> process.report.writeReport();
Writing Node.js report to file: report.20181126.091102.8480.0.001.json
Node.js report completed
> 

当写入报告时,将开始和结束消息发送到标准错误,并将报告的文件名返回给调用者。默认文件名包括日期、时间、PID、和序列号。如果为同一个 Node.js 进程多次生成,则序列号有助于将报告转储与运行时状态相关联

¥When a report is written, start and end messages are issued to stderr and the filename of the report is returned to the caller. The default filename includes the date, time, PID, and a sequence number. The sequence number helps in associating the report dump with the runtime state if generated multiple times for the same Node.js process.

诊断报告有一个相关的个位数版本号(report.header.reportVersion),唯一代表报告格式。添加或删除新键或更改值的数据类型时,版本号会增加。报告版本定义在 LTS 版本中是一致的。

¥Diagnostic report has an associated single-digit version number (report.header.reportVersion), uniquely representing the report format. The version number is bumped when new key is added or removed, or the data type of a value is changed. Report version definitions are consistent across LTS releases.

配置#

¥Configuration

报告生成的其他运行时配置可通过 process.report 的以下属性获得:

¥Additional runtime configuration of report generation is available via the following properties of process.report:

当为 true 时,reportOnFatalError 触发致命错误的诊断报告。默认为 false

¥reportOnFatalError triggers diagnostic reporting on fatal errors when true. Defaults to false.

当为 true 时,reportOnSignal 触发信号的诊断报告。Windows 不支持此。默认为 false

¥reportOnSignal triggers diagnostic reporting on signal when true. This is not supported on Windows. Defaults to false.

当为 true 时,reportOnUncaughtException 触发未捕获异常的诊断报告。默认为 false

¥reportOnUncaughtException triggers diagnostic reporting on uncaught exception when true. Defaults to false.

signal 指定将用于拦截外部触发器以生成报告的 POSIX 信号标识符默认为 'SIGUSR2'

¥signal specifies the POSIX signal identifier that will be used to intercept external triggers for report generation. Defaults to 'SIGUSR2'.

filename 指定文件系统中输出文件的名称。stdoutstderr 附有特殊含义。使用这些将导致报告被写入相关的标准流。在使用标准流的情况下,directory 中的值将被忽略。不支持网址。默认为包含时间戳、PID、和序列号的复合文件名。

¥filename specifies the name of the output file in the file system. Special meaning is attached to stdout and stderr. Usage of these will result in report being written to the associated standard streams. In cases where standard streams are used, the value in directory is ignored. URLs are not supported. Defaults to a composite filename that contains timestamp, PID, and sequence number.

directory 指定将写入报告的文件系统目录。不支持网址。默认为 Node.js 进程的当前工作目录。

¥directory specifies the file system directory where the report will be written. URLs are not supported. Defaults to the current working directory of the Node.js process.

// Trigger report only on uncaught exceptions.
process.report.reportOnFatalError = false;
process.report.reportOnSignal = false;
process.report.reportOnUncaughtException = true;

// Trigger report for both internal errors as well as external signal.
process.report.reportOnFatalError = true;
process.report.reportOnSignal = true;
process.report.reportOnUncaughtException = false;

// Change the default signal to 'SIGQUIT' and enable it.
process.report.reportOnFatalError = false;
process.report.reportOnUncaughtException = false;
process.report.reportOnSignal = true;
process.report.signal = 'SIGQUIT'; 

模块初始化的配置也可以通过环境变量获得:

¥Configuration on module initialization is also available via environment variables:

NODE_OPTIONS="--report-uncaught-exception \
  --report-on-fatalerror --report-on-signal \
  --report-signal=SIGUSR2  --report-filename=./report.json \
  --report-directory=/home/nodeuser" 

具体的 API 文档可以在 process API documentation 章节下找到。

¥Specific API documentation can be found under process API documentation section.

与工作线程互动#

¥Interaction with workers

Worker 线程可以像主线程一样创建报告。

¥Worker threads can create reports in the same way that the main thread does.

报告将包括作为 workers 部分的一部分的当前线程的子线程的任何工作线程的信息,每个工作线程以标准报告格式生成报告。

¥Reports will include information on any Workers that are children of the current thread as part of the workers section, with each Worker generating a report in the standard report format.

生成报告的线程将等待工作线程的报告完成。但是,由于运行 JavaScript 和事件循环都被中断以生成报告,因此延迟通常很低。

¥The thread which is generating the report will wait for the reports from Worker threads to finish. However, the latency for this will usually be low, as both running JavaScript and the event loop are interrupted to generate the report.