Node.js v16.20.2 文档


诊断报告#>

【Diagnostic report】

提供 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": 1,
    "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": {
    "userCpuSeconds": 0.069595,
    "kernelCpuSeconds": 0.019163,
    "cpuConsumptionPercent": 0.000000,
    "maxRss": 18079744,
    "pageFaults": {
      "IORequired": 0,
      "IONotRequired": 4610
    },
    "fsActivity": {
      "reads": 0,
      "writes": 0
    }
  },
  "uvthreadResourceUsage": {
    "userCpuSeconds": 0.068457,
    "kernelCpuSeconds": 0.019127,
    "cpuConsumptionPercent": 0.000000,
    "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-on-signal 允许在接收到指定的(或预定义的)信号时生成报告,以作用于正在运行的 Node.js 进程。(见下文关于如何修改触发报告的信号。)默认信号是 SIGUSR2。当需要从另一个程序触发报告时,这个功能非常有用。应用监控器可以利用该功能定期收集报告,并将丰富的内部运行时数据绘制到它们的视图中。

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-compact 以紧凑格式生成报告,单行 JSON,比默认为人类阅读设计的多行格式更容易被日志处理系统使用。
  • --report-directory 生成报告的位置。
  • --report-filename 报告将被写入的文件名。
  • --report-signal 设置或重置报告生成的信号(不支持 Windows)。默认信号是 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 堆栈的上下文。当在回调或异常处理程序中使用 report 来处理错误时,这允许报告包含原始错误的位置以及错误被处理的位置。

【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 REPL 触发示例报告:

【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
> 

当报告被写入时,会向标准错误输出(stderr)发送开始和结束的消息,并将报告的文件名返回给调用者。默认的文件名包括日期、时间、进程ID(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.】

配置#>

【Configuration】

报告生成的附加运行时配置可以通过 process.report 的以下属性进行设置:

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

reportOnFatalError 在为 true 时会在发生致命错误时触发诊断报告。默认值为 false

reportOnSignal 在为 true 时会在信号发生时触发诊断报告。Windows 不支持此功能。默认值为 false

reportOnUncaughtException 在未捕获的异常发生时触发诊断报告,当设置为 true 时生效。默认值为 false

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

filename 指定文件系统中输出文件的名称。stdoutstderr 有特殊意义。使用它们将导致报告写入关联的标准流。在使用标准流的情况下,会忽略 directory 的值。不支持 URL。默认情况下,文件名为包含时间戳、进程 ID 和序列号的复合文件名。

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

// 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 的信息,作为 workers 部分的一部分,每个 Worker 都会以标准报告格式生成报告。

【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.】

Node.js 中文网 - 粤ICP备13048890号