诊断通道#

稳定性: 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)#

检查是否有活动订阅者订阅了命名通道。如果您要发送的消息可能很昂贵,这将很有帮助。

此 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 <string> | <symbol> 通道名称
  • 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 - 实验性

删除之前使用 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 <Function> 要在进入存储上下文时运行的处理程序
  • thisArg <any> 要用于函数调用的接收器。
  • ...args <any> 要传递给函数的可选参数。

将给定的数据应用于绑定到通道的所有 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 事件。这将使用 start 通道上的 channel.runStores(context, ...) 运行给定函数,确保所有事件都应具有与该跟踪上下文匹配的任何绑定存储。

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 <Function> 用于包装跟踪的回调函数
  • position <number> 预期回调的零索引参数位置(如果传递 undefined,则默认为最后一个参数)
  • context <Object> 用于关联跟踪事件的共享对象(如果传递 undefined,则默认为 {}
  • thisArg <any> 用于函数调用的接收者
  • ...args <any> 传递给函数的参数(必须包含回调)
  • 返回值: <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 代表单个可跟踪操作执行生命周期的特定点。行为分为五个 diagnostics_channels,包括 startendasyncStartasyncEnderror。单个可跟踪操作将在所有事件之间共享相同的事件对象,这对于通过弱映射管理关联很有帮助。

当任务“完成”时,这些事件对象将扩展 resulterror 值。对于同步任务,result 将是返回值,error 将是函数抛出的任何内容。对于基于回调的异步函数,result 将是回调的第二个参数,而 error 将是 end 事件中可见的抛出错误,或者 asyncStartasyncEnd 事件中的第一个回调参数。

跟踪通道应遵循以下命名模式:

  • 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 事件表示函数调用返回值的点。对于异步函数,这是返回的 Promise 完成时,而不是函数本身在内部执行 return 语句时。此时,如果跟踪的函数是同步的,则 result 字段将设置为函数的返回值。或者,error 字段可能存在以表示任何抛出的错误。

建议专门监听 error 事件以跟踪错误,因为可跟踪操作可能产生多个错误。例如,失败的异步任务可能在同步部分的任务内部抛出错误之前启动。

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

asyncStart 事件表示可跟踪函数的回调或延续被触发的点。此时,回调参数等内容可能可用,或者任何其他表达操作“结果”的内容。

对于基于回调的函数,如果回调的第一个参数不是 `undefined` 或 `null`,则它将被分配给 `error` 字段,第二个参数将被分配给 `result` 字段。

对于 Promise,`resolve` 路径的参数将被分配给 `result`,或者 `reject` 路径的参数将被分配给 `error`。

建议专门监听 error 事件以跟踪错误,因为可跟踪操作可能产生多个错误。例如,失败的异步任务可能在同步部分的任务内部抛出错误之前启动。

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

asyncEnd 事件表示异步函数返回的回调。事件数据在 asyncStart 事件之后不太可能发生变化,但查看回调完成的点可能很有用。

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

error 事件表示可跟踪函数同步或异步产生的任何错误。如果在可跟踪函数的同步部分抛出错误,则错误将被分配给事件的 `error` 字段,并且将触发 `error` 事件。如果通过回调或 Promise 拒绝异步接收错误,它也将被分配给事件的 `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 或管道客户端套接字时发出。

net.server.socket

当收到新的 TCP 或管道连接时发出。

UDP#

udp.socket

当创建新的 UDP 套接字时发出。

Process#

child_process

当创建新进程时发出。

Worker Thread#

worker_threads

当创建新线程时发出。