Node.js v20.2.0 文档


目录

诊断通道#

稳定性: 2 - 稳定

源代码: lib/diagnostics_channel.js

node:diagnostics_channel 模块提供了一个 API 来创建命名通道来报告任意消息数据以用于诊断目的。

可以使用以下方式访问它:

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

希望报告诊断消息的模块编写者将创建一个或多个顶层通道来报告消息。 也可以在运行时获取通道,但由于这样做会产生额外的开销,因此不鼓励这样做。 为方便起见,可以导出通道,但只要知道名称,就可以在任何地方获取。

如果您打算让您的模块生成诊断数据以供其他人使用,建议您包含使用哪些命名通道的文档以及消息数据的形状。 通道名称通常应包括模块名称,以避免与其他模块的数据发生冲突。

公共接口#

概述#

以下是公共 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#
  • 返回: <boolean> 如果有活跃订阅者

检查此通道是否有活跃订阅者。 如果您要发送的消息的准备成本可能很高,这将很有帮助。

此 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) 提供了转换函数,它将在消息数据成为商店的上下文值之前应用于转换消息数据。 在需要上下文链接的情况下,可以从转换函数中访问先前的存储上下文。

应用到存储的上下文应该可以在任何异步代码中访问,这些代码从给定函数期间开始的执行继续,但是在某些情况下可能会出现 context loss

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

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> 预期回调的零索引参数位置
  • context <Object> 用于关联跟踪事件的共享对象
  • thisArg <any> 用于函数调用的接收器
  • ...args <any> 传递给函数的可选参数
  • 返回: <any> 给定函数的返回值

跟踪回调接收函数调用。 这将始终围绕函数执行的同步部分生成 start 事件end 事件,并将围绕回调执行生成 asyncStart 事件asyncEnd 事件。 如果给定的函数抛出错误或返回的promise被拒绝,它也可能产生一个 error 事件。 这将在 start 通道上使用 channel.runStores(context, ...) 运行给定函数,确保所有事件都应设置任何绑定存储以匹配此跟踪上下文。

默认情况下,position 将为 -1 以指示应将最终参数用作回调。

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 是多个诊断通道的集合,表示单个可跟踪操作的执行生命周期中的特定点。 该行为分为五个诊断通道,包括 startendasyncStartasyncEnderror。 单个可跟踪操作将在所有事件之间共享相同的事件对象,这有助于通过 weakmap 管理相关性。

当任务 "completes" 时,这些事件对象将使用 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 事件表示正在到达的可跟踪函数的回调或继续。 此时回调参数之类的东西可能可用,或者任何其他表达操作的 "result" 的东西。

对于基于回调的函数,回调的第一个参数将分配给 error 字段,如果不是 undefinednull,第二个参数将分配给 result 字段。

对于 promises,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 套接字时触发。

进程#

child_process

创建新进程时触发。

工作线程#

worker_threads

创建新线程时触发。