跟踪事件#

稳定性:1 - 实验性

node:trace_events 模块提供了一种集中化机制,用于汇总由 V8、Node.js 核心代码及用户空间代码生成的跟踪信息。

可以通过 --trace-event-categories 命令行标志或使用 node:trace_events 模块来启用跟踪。--trace-event-categories 标志接受以逗号分隔的类别名称列表。

可用类别如下:

  • node:一个空的占位符。
  • node.async_hooks:启用对详细 async_hooks 跟踪数据的捕获。async_hooks 事件具有唯一的 asyncId 以及特殊的 triggerId(即 triggerAsyncId)属性。
  • node.bootstrap:启用对 Node.js 引导程序里程碑的捕获。
  • node.console:启用对 console.time()console.count() 输出的捕获。
  • node.threadpoolwork.sync:启用对线程池同步操作(如 blobzlibcryptonode_api)的跟踪数据捕获。
  • node.threadpoolwork.async:启用对线程池异步操作(如 blobzlibcryptonode_api)的跟踪数据捕获。
  • node.dns.native:启用对 DNS 查询跟踪数据的捕获。
  • node.net.native:启用对网络跟踪数据的捕获。
  • node.environment:启用对 Node.js 环境里程碑的捕获。
  • node.fs.sync:启用对文件系统同步方法跟踪数据的捕获。
  • node.fs_dir.sync:启用对文件系统同步目录方法跟踪数据的捕获。
  • node.fs.async:启用对文件系统异步方法跟踪数据的捕获。
  • node.fs_dir.async:启用对文件系统异步目录方法跟踪数据的捕获。
  • node.perf:启用对 Performance API 测量数据的捕获。
    • node.perf.usertiming:仅启用对 Performance API 用户计时(User Timing)度量和标记的捕获。
    • node.perf.timerify:仅启用对 Performance API timerify 测量数据的捕获。
  • node.promises.rejections:启用对跟踪未处理的 Promise 拒绝以及拒绝后已处理的 Promise 数量的跟踪数据捕获。
  • node.vm.script:启用对 node:vm 模块的 runInNewContext()runInContext()runInThisContext() 方法的跟踪数据捕获。
  • v8V8 事件,与垃圾回收 (GC)、编译和执行相关。
  • node.http:启用对 HTTP 请求/响应跟踪数据的捕获。
  • node.module_timer:启用对 CJS 模块加载跟踪数据的捕获。

默认情况下,启用 nodenode.async_hooksv8 类别。

node --trace-event-categories v8,node,node.async_hooks server.js

旧版本的 Node.js 需要使用 --trace-events-enabled 标志来启用跟踪事件。该要求已被移除。但是,--trace-events-enabled 标志仍然可以使用,它将默认启用 nodenode.async_hooksv8 跟踪事件类别。

node --trace-events-enabled

# is equivalent to

node --trace-event-categories v8,node,node.async_hooks

或者,可以使用 node:trace_events 模块来启用跟踪事件。

import { createTracing } from 'node:trace_events';
const tracing = createTracing({ categories: ['node.perf'] });
tracing.enable();  // Enable trace event capture for the 'node.perf' category

// do work

tracing.disable();  // Disable trace event capture for the 'node.perf' category
const { createTracing } = require('node:trace_events');
const tracing = createTracing({ categories: ['node.perf'] });
tracing.enable();  // Enable trace event capture for the 'node.perf' category

// do work

tracing.disable();  // Disable trace event capture for the 'node.perf' category

在启用跟踪的情况下运行 Node.js 将生成日志文件,这些文件可以在 Chrome 的 chrome://tracing 标签页中打开。

日志文件默认命名为 node_trace.${rotation}.log,其中 ${rotation} 是一个递增的日志轮换 ID。文件路径模式可以通过 --trace-event-file-pattern 指定,该参数接受一个支持 ${rotation}${pid} 的模板字符串。

node --trace-event-categories v8 --trace-event-file-pattern '${pid}-${rotation}.log' server.js

为确保在 SIGINTSIGTERMSIGBREAK 等信号事件后能正确生成日志文件,请确保代码中包含相应的处理程序,例如:

process.on('SIGINT', function onSigint() {
  console.info('Received SIGINT.');
  process.exit(130);  // Or applicable exit code depending on OS and signal
});

跟踪系统使用的时钟源与 process.hrtime() 相同。但是,跟踪事件的时间戳以微秒为单位,而 process.hrtime() 返回的是纳秒。

此模块的功能在 Worker 线程中不可用。

node:trace_events 模块#

Tracing 对象#

Tracing 对象用于为一组类别启用或禁用跟踪。实例通过 trace_events.createTracing() 方法创建。

创建时,Tracing 对象处于禁用状态。调用 tracing.enable() 方法会将类别添加到已启用的跟踪事件类别集合中。调用 tracing.disable() 将从已启用的跟踪事件类别集合中移除这些类别。

tracing.categories#

一个以逗号分隔的字符串,包含此 Tracing 对象所涵盖的跟踪事件类别。

tracing.disable()#

禁用此 Tracing 对象。

只有未被其他已启用的 Tracing 对象覆盖且未由 --trace-event-categories 标志指定的跟踪事件类别才会被禁用。

import { createTracing, getEnabledCategories } from 'node:trace_events';
const t1 = createTracing({ categories: ['node', 'v8'] });
const t2 = createTracing({ categories: ['node.perf', 'node'] });
t1.enable();
t2.enable();

// Prints 'node,node.perf,v8'
console.log(getEnabledCategories());

t2.disable(); // Will only disable emission of the 'node.perf' category

// Prints 'node,v8'
console.log(getEnabledCategories());
const { createTracing, getEnabledCategories } = require('node:trace_events');
const t1 = createTracing({ categories: ['node', 'v8'] });
const t2 = createTracing({ categories: ['node.perf', 'node'] });
t1.enable();
t2.enable();

// Prints 'node,node.perf,v8'
console.log(getEnabledCategories());

t2.disable(); // Will only disable emission of the 'node.perf' category

// Prints 'node,v8'
console.log(getEnabledCategories());
tracing.enable()#

Tracing 对象涵盖的类别集合启用此 Tracing 对象。

tracing.enabled#
  • 类型:<boolean> 仅当 Tracing 对象已启用时为 true

trace_events.createTracing(options)#

  • options <Object>
  • categories <string[]> 跟踪类别名称数组。数组中包含的值在可能的情况下会强制转换为字符串。如果值无法转换,将抛出错误。
  • 返回:<Tracing>
  • 为给定的 categories 集合创建并返回一个 Tracing 对象。

    import { createTracing } from 'node:trace_events';
    const categories = ['node.perf', 'node.async_hooks'];
    const tracing = createTracing({ categories });
    tracing.enable();
    // do stuff
    tracing.disable();
    const { createTracing } = require('node:trace_events');
    const categories = ['node.perf', 'node.async_hooks'];
    const tracing = createTracing({ categories });
    tracing.enable();
    // do stuff
    tracing.disable();
    

    trace_events.getEnabledCategories()#

    返回所有当前已启用的跟踪事件类别的逗号分隔列表。当前已启用的跟踪事件类别集合由所有当前已启用的 Tracing 对象以及任何通过 --trace-event-categories 标志启用的类别的并集确定。

    对于以下文件 test.js,命令 node --trace-event-categories node.perf test.js 将在控制台打印 'node.async_hooks,node.perf'

    import { createTracing, getEnabledCategories } from 'node:trace_events';
    const t1 = createTracing({ categories: ['node.async_hooks'] });
    const t2 = createTracing({ categories: ['node.perf'] });
    const t3 = createTracing({ categories: ['v8'] });
    
    t1.enable();
    t2.enable();
    
    console.log(getEnabledCategories());
    const { createTracing, getEnabledCategories } = require('node:trace_events');
    const t1 = createTracing({ categories: ['node.async_hooks'] });
    const t2 = createTracing({ categories: ['node.perf'] });
    const t3 = createTracing({ categories: ['v8'] });
    
    t1.enable();
    t2.enable();
    
    console.log(getEnabledCategories());
    

    示例#

    通过检查器(inspector)收集跟踪事件数据#

    import { Session } from 'node:inspector';
    const session = new Session();
    session.connect();
    
    function post(message, data) {
      return new Promise((resolve, reject) => {
        session.post(message, data, (err, result) => {
          if (err)
            reject(new Error(JSON.stringify(err)));
          else
            resolve(result);
        });
      });
    }
    
    async function collect() {
      const data = [];
      session.on('NodeTracing.dataCollected', (chunk) => data.push(chunk));
      session.on('NodeTracing.tracingComplete', () => {
        // done
      });
      const traceConfig = { includedCategories: ['v8'] };
      await post('NodeTracing.start', { traceConfig });
      // do something
      setTimeout(() => {
        post('NodeTracing.stop').then(() => {
          session.disconnect();
          console.log(data);
        });
      }, 1000);
    }
    
    collect();
    'use strict';
    
    const { Session } = require('node:inspector');
    const session = new Session();
    session.connect();
    
    function post(message, data) {
      return new Promise((resolve, reject) => {
        session.post(message, data, (err, result) => {
          if (err)
            reject(new Error(JSON.stringify(err)));
          else
            resolve(result);
        });
      });
    }
    
    async function collect() {
      const data = [];
      session.on('NodeTracing.dataCollected', (chunk) => data.push(chunk));
      session.on('NodeTracing.tracingComplete', () => {
        // done
      });
      const traceConfig = { includedCategories: ['v8'] };
      await post('NodeTracing.start', { traceConfig });
      // do something
      setTimeout(() => {
        post('NodeTracing.stop').then(() => {
          session.disconnect();
          console.log(data);
        });
      }, 1000);
    }
    
    collect();