Node.js Diagnostics Channel:解耦你的業務邏輯與監控程式碼
在開發大型生產環境應用時,我們通常需要監控 API 的響應時間、資料庫查詢的頻率或是快取的命中率。傳統做法是在業務邏輯中夾雜大量的日誌或是監控上報程式碼:
// 傳統侵入式寫法
async function getUser(id) {
const start = Date.now();
const user = await db.query(id);
metrics.report('db_time', Date.now() - start); // 業務邏輯中混入了監控
return user;
}
這會讓程式碼變得難以維護且難以測試。node:diagnostics_channel 模組提供了一個「發佈/訂閱」機制,讓你能完全解耦業務邏輯與診斷數據。
核心原理:發佈與訂閱
診斷頻道的核心概念是建立一個命名的管道。生產者 (Producers) 負責發送數據,而消費者 (Consumers) 負責接收並處理(如轉發到 Prometheus 或 Datadog)。
實戰開發:實作一個解耦的資料庫監控
1. 定義頻道與發送數據 (生產者)
在你的資料庫模組或基礎元件中,只需專注於發送事件。
const dc = require('node:diagnostics_channel');
// 建立或獲取一個名為 'db.query' 的頻道
const channel = dc.channel('db.query');
async function performQuery(sql) {
const startTime = process.hrtime();
// 執行業務邏輯...
const result = await someDbDriver.execute(sql);
// 如果頻道有人訂閱,則發送診斷數據
if (channel.hasSubscribers) {
channel.publish({
sql,
duration: process.hrtime(startTime),
status: 'success',
});
}
return result;
}
2. 接收數據並進行上報 (消費者)
在程式的入口點 (Entry point) 或專門的監控模組中訂閱數據。
const dc = require('node:diagnostics_channel');
// 訂閱特定頻道
dc.subscribe('db.query', (message, name) => {
console.log(`[監控] 收到 SQL 執行紀錄: ${message.sql}`);
console.log(`[監控] 耗時: ${message.duration[1] / 1000000} ms`);
});
內建頻道的強大力量
Node.js 核心模組(如 http、net)已經內建了許多診斷頻道。你不需要修改 Node.js 的原始碼,就能監聽到內部事件。
例如,監控所有對外的 HTTP 請求:
const dc = require('node:diagnostics_channel');
dc.subscribe('undici:request:create', ({ request }) => {
console.log(`偵測到對外連線:${request.method} ${request.origin}`);
});
為什麼選擇 Diagnostics Channel?
- 極致效能:如果沒有人訂閱頻道,
publish幾乎不會產生任何運算開銷。 - 完全解耦:監控邏輯與業務邏輯分開存放,測試業務邏輯時不需要 Mock 複雜的監控 API。
- OpenTelemetry 友好:它是現代 APM 工具(如 OpenTelemetry Node SDK)底層獲取核心數據的主要手段。
總結
diagnostics_channel是企業級應用實現無侵入監控的關鍵。- 透過
channel.publish與dc.subscribe實現邏輯分離。 - 善用 Node.js 內建的頻道,能讓你對系統運行狀況有更深度的洞察。