跟蹤事件#

穩定性:1 - 實驗性

原始碼: lib/trace_events.js

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 rejection 和之後被處理的 rejection 數量的跟蹤資料。
  • 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' categoryconst { 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.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();