診斷通道#

穩定性:2 - 穩定

原始碼: lib/diagnostics_channel.js

node:diagnostics_channel 模組提供一個 API 來建立命名通道,以報告任意訊息資料供診斷使用。

可以使用以下方式存取

import diagnostics_channel from 'node:diagnostics_channel';const diagnostics_channel = require('node:diagnostics_channel');

如果模組撰寫者想要報告診斷訊息,會建立一個或多個頂層通道來報告訊息。也可以在執行階段取得通道,但由於這樣做會產生額外的負擔,因此不建議這麼做。通道可以匯出以方便使用,但只要知道名稱,就可以在任何地方取得。

如果您打算讓模組產生診斷資料供其他人使用,建議您包含已使用命名頻道的文件,以及訊息資料的形狀。頻道名稱通常應包含模組名稱,以避免與其他模組的資料發生衝突。

公開 API#

概觀#

以下是公開 API 的簡單概觀。

import diagnostics_channel from 'node:diagnostics_channel';

// Get a reusable channel object
const channel = diagnostics_channel.channel('my-channel');

function onMessage(message, name) {
  // Received data
}

// Subscribe to the channel
diagnostics_channel.subscribe('my-channel', onMessage);

// Check if the channel has an active subscriber
if (channel.hasSubscribers) {
  // Publish data to the channel
  channel.publish({
    some: 'data',
  });
}

// Unsubscribe from the channel
diagnostics_channel.unsubscribe('my-channel', onMessage);const diagnostics_channel = require('node:diagnostics_channel');

// Get a reusable channel object
const channel = diagnostics_channel.channel('my-channel');

function onMessage(message, name) {
  // Received data
}

// Subscribe to the channel
diagnostics_channel.subscribe('my-channel', onMessage);

// Check if the channel has an active subscriber
if (channel.hasSubscribers) {
  // Publish data to the channel
  channel.publish({
    some: 'data',
  });
}

// Unsubscribe from the channel
diagnostics_channel.unsubscribe('my-channel', onMessage);
diagnostics_channel.hasSubscribers(name)#

檢查是否有 active 訂閱者訂閱已命名的頻道。如果您要傳送的訊息準備起來可能很花費成本,這會很有幫助。

此 API 是選用的,但在嘗試從效能很敏感的程式碼發布訊息時很有幫助。

import diagnostics_channel from 'node:diagnostics_channel';

if (diagnostics_channel.hasSubscribers('my-channel')) {
  // There are subscribers, prepare and publish message
}const diagnostics_channel = require('node:diagnostics_channel');

if (diagnostics_channel.hasSubscribers('my-channel')) {
  // There are subscribers, prepare and publish message
}
diagnostics_channel.channel(name)#

這是想要發布到已命名頻道的任何人的主要入門點。它會產生一個頻道物件,該物件經過最佳化,以盡可能減少發布時的開銷。

import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');
diagnostics_channel.subscribe(name, onMessage)#

註冊訊息處理程式以訂閱此頻道。每當訊息發佈到頻道時,此訊息處理程式將會同步執行。訊息處理程式中引發的任何錯誤都會觸發 'uncaughtException'

import diagnostics_channel from 'node:diagnostics_channel';

diagnostics_channel.subscribe('my-channel', (message, name) => {
  // Received data
});const diagnostics_channel = require('node:diagnostics_channel');

diagnostics_channel.subscribe('my-channel', (message, name) => {
  // Received data
});
diagnostics_channel.unsubscribe(name, onMessage)#
  • name <字串> | <符號> 頻道名稱
  • onMessage <Function> 要移除的前一個訂閱處理程式
  • 傳回:<boolean> 如果找到處理程式,則為 true,否則為 false

移除先前使用 diagnostics_channel.subscribe(name, onMessage) 註冊到此頻道的訊息處理程式。

import diagnostics_channel from 'node:diagnostics_channel';

function onMessage(message, name) {
  // Received data
}

diagnostics_channel.subscribe('my-channel', onMessage);

diagnostics_channel.unsubscribe('my-channel', onMessage);const diagnostics_channel = require('node:diagnostics_channel');

function onMessage(message, name) {
  // Received data
}

diagnostics_channel.subscribe('my-channel', onMessage);

diagnostics_channel.unsubscribe('my-channel', onMessage);
diagnostics_channel.tracingChannel(nameOrChannels)#

穩定性:1 - 實驗性

為指定的 TracingChannel 頻道 建立 TracingChannel 封裝器。如果給定名稱,將以 tracing:${name}:${eventType} 的形式建立對應的追蹤頻道,其中 eventType 對應於 TracingChannel 頻道 的類型。

import diagnostics_channel from 'node:diagnostics_channel';

const channelsByName = diagnostics_channel.tracingChannel('my-channel');

// or...

const channelsByCollection = diagnostics_channel.tracingChannel({
  start: diagnostics_channel.channel('tracing:my-channel:start'),
  end: diagnostics_channel.channel('tracing:my-channel:end'),
  asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'),
  asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'),
  error: diagnostics_channel.channel('tracing:my-channel:error'),
});const diagnostics_channel = require('node:diagnostics_channel');

const channelsByName = diagnostics_channel.tracingChannel('my-channel');

// or...

const channelsByCollection = diagnostics_channel.tracingChannel({
  start: diagnostics_channel.channel('tracing:my-channel:start'),
  end: diagnostics_channel.channel('tracing:my-channel:end'),
  asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'),
  asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'),
  error: diagnostics_channel.channel('tracing:my-channel:error'),
});

類別:Channel#

類別 Channel 代表資料管道中個別命名的頻道。它用於追蹤訂閱者,並在有訂閱者時發佈訊息。它作為一個獨立的物件存在,以避免在發佈時查詢頻道,這能讓發佈速度非常快,並允許大量使用,同時產生非常低的成本。頻道使用 diagnostics_channel.channel(name) 建立,直接使用 new Channel(name) 建立頻道不受支援。

channel.hasSubscribers#

檢查此頻道是否有活躍的訂閱者。如果你要傳送的訊息準備起來很昂貴,這會很有幫助。

此 API 是選用的,但在嘗試從效能很敏感的程式碼發布訊息時很有幫助。

import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');

if (channel.hasSubscribers) {
  // There are subscribers, prepare and publish message
}const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');

if (channel.hasSubscribers) {
  // There are subscribers, prepare and publish message
}
channel.publish(message)#
  • message <any> 要傳送給頻道訂閱者的訊息

向頻道的任何訂閱者發佈訊息。這會同步觸發訊息處理常式,因此它們會在同一個內容中執行。

import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');

channel.publish({
  some: 'message',
});const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');

channel.publish({
  some: 'message',
});
channel.subscribe(onMessage)#

註冊訊息處理程式以訂閱此頻道。每當訊息發佈到頻道時,此訊息處理程式將會同步執行。訊息處理程式中引發的任何錯誤都會觸發 'uncaughtException'

import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');

channel.subscribe((message, name) => {
  // Received data
});const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');

channel.subscribe((message, name) => {
  // Received data
});
channel.unsubscribe(onMessage)#

  • onMessage <Function> 要移除的前一個訂閱處理程式
  • 傳回:<boolean> 如果找到處理程式,則為 true,否則為 false

移除先前使用 channel.subscribe(onMessage) 註冊到此頻道的訊息處理常式。

import diagnostics_channel from 'node:diagnostics_channel';

const channel = diagnostics_channel.channel('my-channel');

function onMessage(message, name) {
  // Received data
}

channel.subscribe(onMessage);

channel.unsubscribe(onMessage);const diagnostics_channel = require('node:diagnostics_channel');

const channel = diagnostics_channel.channel('my-channel');

function onMessage(message, name) {
  // Received data
}

channel.subscribe(onMessage);

channel.unsubscribe(onMessage);
channel.bindStore(store[, transform])#

穩定性:1 - 實驗性

當呼叫 channel.runStores(context, ...) 時,所提供的內容資料將套用至繫結到頻道的任何儲存區。如果儲存區已經繫結,則前一個 transform 函式將會被新的函式取代。可以省略 transform 函式,以將所提供的內容資料直接設定為內容。

import diagnostics_channel from 'node:diagnostics_channel';
import { AsyncLocalStorage } from 'node:async_hooks';

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store, (data) => {
  return { data };
});const diagnostics_channel = require('node:diagnostics_channel');
const { AsyncLocalStorage } = require('node:async_hooks');

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store, (data) => {
  return { data };
});
channel.unbindStore(store)#

穩定性:1 - 實驗性

  • store <AsyncLocalStorage> 要從頻道解除繫結的儲存區。
  • 傳回:<boolean> 如果找到儲存區,則為 true,否則為 false

移除先前使用 channel.bindStore(store) 註冊到此頻道的訊息處理常式。

import diagnostics_channel from 'node:diagnostics_channel';
import { AsyncLocalStorage } from 'node:async_hooks';

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store);
channel.unbindStore(store);const diagnostics_channel = require('node:diagnostics_channel');
const { AsyncLocalStorage } = require('node:async_hooks');

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store);
channel.unbindStore(store);
channel.runStores(context, fn[, thisArg[, ...args]])#

穩定性:1 - 實驗性

  • context <any> 要傳送給訂閱者並繫結到儲存區的訊息
  • fn <函數> 處理器在輸入的儲存內容中執行
  • thisArg <任何> 用於函數呼叫的接收器。
  • ...args <任何> 傳遞給函數的選用引數。

在給定函數持續時間內,將給定的資料套用至繫結至頻道的任何 AsyncLocalStorage 實例,然後在資料套用至儲存的範圍內發佈至頻道。

如果轉換函數已提供給 channel.bindStore(store),它將套用於轉換訊息資料,然後才成為儲存的內容值。在需要內容連結的情況下,可以從轉換函數內取用先前的儲存內容。

套用至儲存的內容應可在任何從給定函數開始執行的非同步程式碼中取用,但有些情況可能會發生 內容遺失

import diagnostics_channel from 'node:diagnostics_channel';
import { AsyncLocalStorage } from 'node:async_hooks';

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store, (message) => {
  const parent = store.getStore();
  return new Span(message, parent);
});
channel.runStores({ some: 'message' }, () => {
  store.getStore(); // Span({ some: 'message' })
});const diagnostics_channel = require('node:diagnostics_channel');
const { AsyncLocalStorage } = require('node:async_hooks');

const store = new AsyncLocalStorage();

const channel = diagnostics_channel.channel('my-channel');

channel.bindStore(store, (message) => {
  const parent = store.getStore();
  return new Span(message, parent);
});
channel.runStores({ some: 'message' }, () => {
  store.getStore(); // Span({ some: 'message' })
});

類別:TracingChannel#

穩定性:1 - 實驗性

類別 TracingChannelTracingChannel 頻道 的集合,它們共同表示單一可追蹤動作。它用於將產生應用程式流程追蹤事件的程序正規化和簡化。diagnostics_channel.tracingChannel() 用於建構 TracingChannel。與 Channel 一樣,建議在檔案頂層建立並重複使用單一 TracingChannel,而不是動態建立。

tracingChannel.subscribe(subscribers)#

穩定性:1 - 實驗性

協助將函式集合訂閱至對應的通道。這與個別呼叫每個通道的 channel.subscribe(onMessage) 相同。

import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.subscribe({
  start(message) {
    // Handle start message
  },
  end(message) {
    // Handle end message
  },
  asyncStart(message) {
    // Handle asyncStart message
  },
  asyncEnd(message) {
    // Handle asyncEnd message
  },
  error(message) {
    // Handle error message
  },
});const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.subscribe({
  start(message) {
    // Handle start message
  },
  end(message) {
    // Handle end message
  },
  asyncStart(message) {
    // Handle asyncStart message
  },
  asyncEnd(message) {
    // Handle asyncEnd message
  },
  error(message) {
    // Handle error message
  },
});
tracingChannel.unsubscribe(subscribers)#

穩定性:1 - 實驗性

協助將函式集合從對應的通道取消訂閱。這與個別呼叫每個通道的 channel.unsubscribe(onMessage) 相同。

import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.unsubscribe({
  start(message) {
    // Handle start message
  },
  end(message) {
    // Handle end message
  },
  asyncStart(message) {
    // Handle asyncStart message
  },
  asyncEnd(message) {
    // Handle asyncEnd message
  },
  error(message) {
    // Handle error message
  },
});const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.unsubscribe({
  start(message) {
    // Handle start message
  },
  end(message) {
    // Handle end message
  },
  asyncStart(message) {
    // Handle asyncStart message
  },
  asyncEnd(message) {
    // Handle asyncEnd message
  },
  error(message) {
    // Handle error message
  },
});
tracingChannel.traceSync(fn[, context[, thisArg[, ...args]]])#

穩定性:1 - 實驗性

  • fn <Function> 要包圍追蹤的函式
  • context <Object> 共用物件,用於關聯事件
  • thisArg <any> 要用於函式呼叫的接收器
  • ...args <any> 要傳遞給函式的選用引數
  • 傳回:<any> 指定函式的傳回值

追蹤同步函式呼叫。這將永遠在執行期間產生 start 事件end 事件,如果指定的函式擲回錯誤,可能會產生 error 事件。這將使用 channel.runStores(context, ...)start 頻道上執行指定的函式,這可確保所有事件應具有設定為符合此追蹤內容的任何繫結儲存體。

import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.traceSync(() => {
  // Do something
}, {
  some: 'thing',
});const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.traceSync(() => {
  // Do something
}, {
  some: 'thing',
});
tracingChannel.tracePromise(fn[, context[, thisArg[, ...args]]])#

穩定性:1 - 實驗性

  • fn <Function> 傳回 Promise 的函式,用於包圍追蹤
  • context <Object> 共用物件,用於關聯追蹤事件
  • thisArg <any> 要用於函式呼叫的接收器
  • ...args <any> 要傳遞給函式的選用引數
  • 傳回:<Promise> 從指定函式傳回的 Promise 串接而來

追蹤傳回 Promise 的函式呼叫。這將永遠在函式執行的同步部分產生 start 事件end 事件,並在到達 Promise 延續時產生 asyncStart 事件asyncEnd 事件。如果指定的函式擲回錯誤或傳回的 Promise 遭拒絕,它也可能會產生 error 事件。這將使用 channel.runStores(context, ...)start 頻道上執行指定的函式,這可確保所有事件應具有設定為符合此追蹤內容的任何繫結儲存體。

import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.tracePromise(async () => {
  // Do something
}, {
  some: 'thing',
});const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.tracePromise(async () => {
  // Do something
}, {
  some: 'thing',
});
tracingChannel.traceCallback(fn, position, context, thisArg, ...args)#

穩定性:1 - 實驗性

  • fn <函式> 使用函式來封裝追蹤的回呼
  • position <數字> 預期回呼的零索引引數位置(如果傳遞 undefined,則預設為最後一個引數)
  • context <物件> 共用物件,用於關聯追蹤事件(如果傳遞 undefined,則預設為 {}
  • thisArg <any> 要用於函式呼叫的接收器
  • ...args <任何> 要傳遞給函式的引數(必須包含回呼)
  • 傳回:<any> 指定函式的傳回值

追蹤接收回呼的函式呼叫。預期回呼遵循錯誤作為第一個引數的慣例。這將始終在函式執行的同步部分周圍產生 start 事件end 事件,並在回呼執行周圍產生 asyncStart 事件asyncEnd 事件。如果給定的函式擲回例外,或設定傳遞給回呼的第一個引數,它也可能會產生 error 事件。這將使用 channel.runStores(context, ...)start 通道上執行給定的函式,這可確保所有事件都應設定任何繫結的儲存體,以符合此追蹤內容。

import diagnostics_channel from 'node:diagnostics_channel';

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.traceCallback((arg1, callback) => {
  // Do something
  callback(null, 'result');
}, 1, {
  some: 'thing',
}, thisArg, arg1, callback);const diagnostics_channel = require('node:diagnostics_channel');

const channels = diagnostics_channel.tracingChannel('my-channel');

channels.traceCallback((arg1, callback) => {
  // Do something
  callback(null, 'result');
}, {
  some: 'thing',
}, thisArg, arg1, callback);

回呼也會使用 channel.runStores(context, ...) 執行,這在某些情況下能復原內容損失。

import diagnostics_channel from 'node:diagnostics_channel';
import { AsyncLocalStorage } from 'node:async_hooks';

const channels = diagnostics_channel.tracingChannel('my-channel');
const myStore = new AsyncLocalStorage();

// The start channel sets the initial store data to something
// and stores that store data value on the trace context object
channels.start.bindStore(myStore, (data) => {
  const span = new Span(data);
  data.span = span;
  return span;
});

// Then asyncStart can restore from that data it stored previously
channels.asyncStart.bindStore(myStore, (data) => {
  return data.span;
});const diagnostics_channel = require('node:diagnostics_channel');
const { AsyncLocalStorage } = require('node:async_hooks');

const channels = diagnostics_channel.tracingChannel('my-channel');
const myStore = new AsyncLocalStorage();

// The start channel sets the initial store data to something
// and stores that store data value on the trace context object
channels.start.bindStore(myStore, (data) => {
  const span = new Span(data);
  data.span = span;
  return span;
});

// Then asyncStart can restore from that data it stored previously
channels.asyncStart.bindStore(myStore, (data) => {
  return data.span;
});

TracingChannel 通道#

TracingChannel 是代表單一可追蹤動作執行生命週期中特定點的 diagnostics_channels 集合。行為會分成五個 diagnostics_channels,包含 startendasyncStartasyncEnderror。單一可追蹤動作會在所有事件之間共用同一個事件物件,這有助於透過 weakmap 管理關聯性。

當任務「完成」時,這些事件物件會延伸為 resulterror 值。對於同步任務,result 會是傳回值,而 error 會是從函式拋出的任何內容。對於基於回呼的非同步函式,result 會是回呼的第二個引數,而 error 會是 end 事件中可見的拋出錯誤,或是 asyncStartasyncEnd 事件中的第一個回呼引數。

Tracing 通道應遵循下列命名模式

  • tracing:module.class.method:starttracing:module.function:start
  • tracing:module.class.method:endtracing:module.function:end
  • tracing:module.class.method:asyncStarttracing:module.function:asyncStart
  • tracing:module.class.method:asyncEndtracing:module.function:asyncEnd
  • tracing:module.class.method:errortracing:module.function:error
start(event)#
  • 名稱:tracing:${name}:start

start 事件代表函式被呼叫的點。在這個點,事件資料可能包含函式引數或函式執行一開始時可用的任何其他內容。

end(event)#
  • 名稱:tracing:${name}:end

end 事件表示函式呼叫傳回值的點。對於非同步函式,這是傳回承諾時,而不是函式本身在內部建立傳回陳述式時。此時,如果追蹤函式是同步的,result 欄位會設定為函式的傳回值。或者,error 欄位可能會出現,以表示任何拋出的錯誤。

建議特別聆聽 error 事件以追蹤錯誤,因為可追蹤動作可能會產生多個錯誤。例如,失敗的非同步任務可能在任務的同步部分拋出錯誤之前在內部啟動。

asyncStart(event)#
  • 名稱:tracing:${name}:asyncStart

asyncStart 事件表示可追蹤函式的回呼或延續已到達。此時,回呼引數等項目可能可用,或任何表達動作「結果」的其他項目。

對於基於回呼的函式,如果回呼的第一個引數不是 undefinednull,則會指派給 error 欄位,而第二個引數會指派給 result 欄位。

對於承諾,resolve 路徑的引數會指派給 result,或 reject 路徑的引數會指派給 error

建議特別聆聽 error 事件以追蹤錯誤,因為可追蹤動作可能會產生多個錯誤。例如,失敗的非同步任務可能在任務的同步部分拋出錯誤之前在內部啟動。

asyncEnd(event)#
  • 名稱:tracing:${name}:asyncEnd

asyncEnd 事件表示非同步函式的回呼傳回。asyncStart 事件後,事件資料不太可能變更,但查看回呼完成的點可能很有用。

error(event)#
  • 名稱:tracing:${name}:error

error 事件表示可追蹤函式同步或非同步產生的任何錯誤。如果在追蹤函式的同步部分擲回錯誤,則錯誤會指派給事件的 error 欄位,且 error 事件會觸發。如果透過回呼或承諾拒絕非同步收到錯誤,也會指派給事件的 error 欄位,並觸發 error 事件。

單一可追蹤函式呼叫有可能多次產生錯誤,因此在使用此事件時應考慮這一點。例如,如果內部觸發另一個非同步工作,而該工作失敗,然後函式的同步部分再擲回錯誤,則會發出兩個 error 事件,一個是同步錯誤,另一個是非同步錯誤。

內建頻道#

穩定性:1 - 實驗性

雖然 diagnostics_channel API 現在被視為穩定,但目前可用的內建頻道並非如此。每個頻道都必須獨立宣告為穩定。

HTTP#

http.client.request.start

當客戶端開始請求時發出。

http.client.response.finish

當客戶端收到回應時發出。

http.server.request.start

伺服器收到請求時發出。

http.server.response.finish

伺服器傳送回應時發出。

NET#

net.client.socket

建立新的 TCP 或管線用戶端 socket 時發出。

net.server.socket

收到新的 TCP 或管線連線時發出。

UDP#

udp.socket

建立新的 UDP socket 時發出。

Process#

child_process

建立新的程序時發出。

工作執行緒#

worker_threads

建立新的執行緒時發出。