c0105f77a84832217257c5fe9e763a6686ef7874e5df8d971a8bbf87899c5ddaea8ce4b8e5e26eeb410d102d6c5f269b79b4d7f9b49507a166cbc527d865e2 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /**
  2. * The `node:diagnostics_channel` module provides an API to create named channels
  3. * to report arbitrary message data for diagnostics purposes.
  4. *
  5. * It can be accessed using:
  6. *
  7. * ```js
  8. * import diagnostics_channel from 'node:diagnostics_channel';
  9. * ```
  10. *
  11. * It is intended that a module writer wanting to report diagnostics messages
  12. * will create one or many top-level channels to report messages through.
  13. * Channels may also be acquired at runtime but it is not encouraged
  14. * due to the additional overhead of doing so. Channels may be exported for
  15. * convenience, but as long as the name is known it can be acquired anywhere.
  16. *
  17. * If you intend for your module to produce diagnostics data for others to
  18. * consume it is recommended that you include documentation of what named
  19. * channels are used along with the shape of the message data. Channel names
  20. * should generally include the module name to avoid collisions with data from
  21. * other modules.
  22. * @since v15.1.0, v14.17.0
  23. * @see [source](https://github.com/nodejs/node/blob/v22.x/lib/diagnostics_channel.js)
  24. */
  25. declare module "diagnostics_channel" {
  26. import { AsyncLocalStorage } from "node:async_hooks";
  27. /**
  28. * Check if there are active subscribers to the named channel. This is helpful if
  29. * the message you want to send might be expensive to prepare.
  30. *
  31. * This API is optional but helpful when trying to publish messages from very
  32. * performance-sensitive code.
  33. *
  34. * ```js
  35. * import diagnostics_channel from 'node:diagnostics_channel';
  36. *
  37. * if (diagnostics_channel.hasSubscribers('my-channel')) {
  38. * // There are subscribers, prepare and publish message
  39. * }
  40. * ```
  41. * @since v15.1.0, v14.17.0
  42. * @param name The channel name
  43. * @return If there are active subscribers
  44. */
  45. function hasSubscribers(name: string | symbol): boolean;
  46. /**
  47. * This is the primary entry-point for anyone wanting to publish to a named
  48. * channel. It produces a channel object which is optimized to reduce overhead at
  49. * publish time as much as possible.
  50. *
  51. * ```js
  52. * import diagnostics_channel from 'node:diagnostics_channel';
  53. *
  54. * const channel = diagnostics_channel.channel('my-channel');
  55. * ```
  56. * @since v15.1.0, v14.17.0
  57. * @param name The channel name
  58. * @return The named channel object
  59. */
  60. function channel(name: string | symbol): Channel;
  61. type ChannelListener = (message: unknown, name: string | symbol) => void;
  62. /**
  63. * Register a message handler to subscribe to this channel. This message handler
  64. * will be run synchronously whenever a message is published to the channel. Any
  65. * errors thrown in the message handler will trigger an `'uncaughtException'`.
  66. *
  67. * ```js
  68. * import diagnostics_channel from 'node:diagnostics_channel';
  69. *
  70. * diagnostics_channel.subscribe('my-channel', (message, name) => {
  71. * // Received data
  72. * });
  73. * ```
  74. * @since v18.7.0, v16.17.0
  75. * @param name The channel name
  76. * @param onMessage The handler to receive channel messages
  77. */
  78. function subscribe(name: string | symbol, onMessage: ChannelListener): void;
  79. /**
  80. * Remove a message handler previously registered to this channel with {@link subscribe}.
  81. *
  82. * ```js
  83. * import diagnostics_channel from 'node:diagnostics_channel';
  84. *
  85. * function onMessage(message, name) {
  86. * // Received data
  87. * }
  88. *
  89. * diagnostics_channel.subscribe('my-channel', onMessage);
  90. *
  91. * diagnostics_channel.unsubscribe('my-channel', onMessage);
  92. * ```
  93. * @since v18.7.0, v16.17.0
  94. * @param name The channel name
  95. * @param onMessage The previous subscribed handler to remove
  96. * @return `true` if the handler was found, `false` otherwise.
  97. */
  98. function unsubscribe(name: string | symbol, onMessage: ChannelListener): boolean;
  99. /**
  100. * Creates a `TracingChannel` wrapper for the given `TracingChannel Channels`. If a name is given, the corresponding tracing
  101. * channels will be created in the form of `tracing:${name}:${eventType}` where `eventType` corresponds to the types of `TracingChannel Channels`.
  102. *
  103. * ```js
  104. * import diagnostics_channel from 'node:diagnostics_channel';
  105. *
  106. * const channelsByName = diagnostics_channel.tracingChannel('my-channel');
  107. *
  108. * // or...
  109. *
  110. * const channelsByCollection = diagnostics_channel.tracingChannel({
  111. * start: diagnostics_channel.channel('tracing:my-channel:start'),
  112. * end: diagnostics_channel.channel('tracing:my-channel:end'),
  113. * asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'),
  114. * asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'),
  115. * error: diagnostics_channel.channel('tracing:my-channel:error'),
  116. * });
  117. * ```
  118. * @since v19.9.0
  119. * @experimental
  120. * @param nameOrChannels Channel name or object containing all the `TracingChannel Channels`
  121. * @return Collection of channels to trace with
  122. */
  123. function tracingChannel<
  124. StoreType = unknown,
  125. ContextType extends object = StoreType extends object ? StoreType : object,
  126. >(
  127. nameOrChannels: string | TracingChannelCollection<StoreType, ContextType>,
  128. ): TracingChannel<StoreType, ContextType>;
  129. /**
  130. * The class `Channel` represents an individual named channel within the data
  131. * pipeline. It is used to track subscribers and to publish messages when there
  132. * are subscribers present. It exists as a separate object to avoid channel
  133. * lookups at publish time, enabling very fast publish speeds and allowing
  134. * for heavy use while incurring very minimal cost. Channels are created with {@link channel}, constructing a channel directly
  135. * with `new Channel(name)` is not supported.
  136. * @since v15.1.0, v14.17.0
  137. */
  138. class Channel<StoreType = unknown, ContextType = StoreType> {
  139. readonly name: string | symbol;
  140. /**
  141. * Check if there are active subscribers to this channel. This is helpful if
  142. * the message you want to send might be expensive to prepare.
  143. *
  144. * This API is optional but helpful when trying to publish messages from very
  145. * performance-sensitive code.
  146. *
  147. * ```js
  148. * import diagnostics_channel from 'node:diagnostics_channel';
  149. *
  150. * const channel = diagnostics_channel.channel('my-channel');
  151. *
  152. * if (channel.hasSubscribers) {
  153. * // There are subscribers, prepare and publish message
  154. * }
  155. * ```
  156. * @since v15.1.0, v14.17.0
  157. */
  158. readonly hasSubscribers: boolean;
  159. private constructor(name: string | symbol);
  160. /**
  161. * Publish a message to any subscribers to the channel. This will trigger
  162. * message handlers synchronously so they will execute within the same context.
  163. *
  164. * ```js
  165. * import diagnostics_channel from 'node:diagnostics_channel';
  166. *
  167. * const channel = diagnostics_channel.channel('my-channel');
  168. *
  169. * channel.publish({
  170. * some: 'message',
  171. * });
  172. * ```
  173. * @since v15.1.0, v14.17.0
  174. * @param message The message to send to the channel subscribers
  175. */
  176. publish(message: unknown): void;
  177. /**
  178. * Register a message handler to subscribe to this channel. This message handler
  179. * will be run synchronously whenever a message is published to the channel. Any
  180. * errors thrown in the message handler will trigger an `'uncaughtException'`.
  181. *
  182. * ```js
  183. * import diagnostics_channel from 'node:diagnostics_channel';
  184. *
  185. * const channel = diagnostics_channel.channel('my-channel');
  186. *
  187. * channel.subscribe((message, name) => {
  188. * // Received data
  189. * });
  190. * ```
  191. * @since v15.1.0, v14.17.0
  192. * @deprecated Since v18.7.0,v16.17.0 - Use {@link subscribe(name, onMessage)}
  193. * @param onMessage The handler to receive channel messages
  194. */
  195. subscribe(onMessage: ChannelListener): void;
  196. /**
  197. * Remove a message handler previously registered to this channel with `channel.subscribe(onMessage)`.
  198. *
  199. * ```js
  200. * import diagnostics_channel from 'node:diagnostics_channel';
  201. *
  202. * const channel = diagnostics_channel.channel('my-channel');
  203. *
  204. * function onMessage(message, name) {
  205. * // Received data
  206. * }
  207. *
  208. * channel.subscribe(onMessage);
  209. *
  210. * channel.unsubscribe(onMessage);
  211. * ```
  212. * @since v15.1.0, v14.17.0
  213. * @deprecated Since v18.7.0,v16.17.0 - Use {@link unsubscribe(name, onMessage)}
  214. * @param onMessage The previous subscribed handler to remove
  215. * @return `true` if the handler was found, `false` otherwise.
  216. */
  217. unsubscribe(onMessage: ChannelListener): void;
  218. /**
  219. * When `channel.runStores(context, ...)` is called, the given context data
  220. * will be applied to any store bound to the channel. If the store has already been
  221. * bound the previous `transform` function will be replaced with the new one.
  222. * The `transform` function may be omitted to set the given context data as the
  223. * context directly.
  224. *
  225. * ```js
  226. * import diagnostics_channel from 'node:diagnostics_channel';
  227. * import { AsyncLocalStorage } from 'node:async_hooks';
  228. *
  229. * const store = new AsyncLocalStorage();
  230. *
  231. * const channel = diagnostics_channel.channel('my-channel');
  232. *
  233. * channel.bindStore(store, (data) => {
  234. * return { data };
  235. * });
  236. * ```
  237. * @since v19.9.0
  238. * @experimental
  239. * @param store The store to which to bind the context data
  240. * @param transform Transform context data before setting the store context
  241. */
  242. bindStore(store: AsyncLocalStorage<StoreType>, transform?: (context: ContextType) => StoreType): void;
  243. /**
  244. * Remove a message handler previously registered to this channel with `channel.bindStore(store)`.
  245. *
  246. * ```js
  247. * import diagnostics_channel from 'node:diagnostics_channel';
  248. * import { AsyncLocalStorage } from 'node:async_hooks';
  249. *
  250. * const store = new AsyncLocalStorage();
  251. *
  252. * const channel = diagnostics_channel.channel('my-channel');
  253. *
  254. * channel.bindStore(store);
  255. * channel.unbindStore(store);
  256. * ```
  257. * @since v19.9.0
  258. * @experimental
  259. * @param store The store to unbind from the channel.
  260. * @return `true` if the store was found, `false` otherwise.
  261. */
  262. unbindStore(store: AsyncLocalStorage<StoreType>): boolean;
  263. /**
  264. * Applies the given data to any AsyncLocalStorage instances bound to the channel
  265. * for the duration of the given function, then publishes to the channel within
  266. * the scope of that data is applied to the stores.
  267. *
  268. * If a transform function was given to `channel.bindStore(store)` it will be
  269. * applied to transform the message data before it becomes the context value for
  270. * the store. The prior storage context is accessible from within the transform
  271. * function in cases where context linking is required.
  272. *
  273. * The context applied to the store should be accessible in any async code which
  274. * continues from execution which began during the given function, however
  275. * there are some situations in which `context loss` may occur.
  276. *
  277. * ```js
  278. * import diagnostics_channel from 'node:diagnostics_channel';
  279. * import { AsyncLocalStorage } from 'node:async_hooks';
  280. *
  281. * const store = new AsyncLocalStorage();
  282. *
  283. * const channel = diagnostics_channel.channel('my-channel');
  284. *
  285. * channel.bindStore(store, (message) => {
  286. * const parent = store.getStore();
  287. * return new Span(message, parent);
  288. * });
  289. * channel.runStores({ some: 'message' }, () => {
  290. * store.getStore(); // Span({ some: 'message' })
  291. * });
  292. * ```
  293. * @since v19.9.0
  294. * @experimental
  295. * @param context Message to send to subscribers and bind to stores
  296. * @param fn Handler to run within the entered storage context
  297. * @param thisArg The receiver to be used for the function call.
  298. * @param args Optional arguments to pass to the function.
  299. */
  300. runStores(): void;
  301. }
  302. interface TracingChannelSubscribers<ContextType extends object> {
  303. start: (message: ContextType) => void;
  304. end: (
  305. message: ContextType & {
  306. error?: unknown;
  307. result?: unknown;
  308. },
  309. ) => void;
  310. asyncStart: (
  311. message: ContextType & {
  312. error?: unknown;
  313. result?: unknown;
  314. },
  315. ) => void;
  316. asyncEnd: (
  317. message: ContextType & {
  318. error?: unknown;
  319. result?: unknown;
  320. },
  321. ) => void;
  322. error: (
  323. message: ContextType & {
  324. error: unknown;
  325. },
  326. ) => void;
  327. }
  328. interface TracingChannelCollection<StoreType = unknown, ContextType = StoreType> {
  329. start: Channel<StoreType, ContextType>;
  330. end: Channel<StoreType, ContextType>;
  331. asyncStart: Channel<StoreType, ContextType>;
  332. asyncEnd: Channel<StoreType, ContextType>;
  333. error: Channel<StoreType, ContextType>;
  334. }
  335. /**
  336. * The class `TracingChannel` is a collection of `TracingChannel Channels` which
  337. * together express a single traceable action. It is used to formalize and
  338. * simplify the process of producing events for tracing application flow. {@link tracingChannel} is used to construct a `TracingChannel`. As with `Channel` it is recommended to create and reuse a
  339. * single `TracingChannel` at the top-level of the file rather than creating them
  340. * dynamically.
  341. * @since v19.9.0
  342. * @experimental
  343. */
  344. class TracingChannel<StoreType = unknown, ContextType extends object = {}> implements TracingChannelCollection {
  345. start: Channel<StoreType, ContextType>;
  346. end: Channel<StoreType, ContextType>;
  347. asyncStart: Channel<StoreType, ContextType>;
  348. asyncEnd: Channel<StoreType, ContextType>;
  349. error: Channel<StoreType, ContextType>;
  350. /**
  351. * Helper to subscribe a collection of functions to the corresponding channels.
  352. * This is the same as calling `channel.subscribe(onMessage)` on each channel
  353. * individually.
  354. *
  355. * ```js
  356. * import diagnostics_channel from 'node:diagnostics_channel';
  357. *
  358. * const channels = diagnostics_channel.tracingChannel('my-channel');
  359. *
  360. * channels.subscribe({
  361. * start(message) {
  362. * // Handle start message
  363. * },
  364. * end(message) {
  365. * // Handle end message
  366. * },
  367. * asyncStart(message) {
  368. * // Handle asyncStart message
  369. * },
  370. * asyncEnd(message) {
  371. * // Handle asyncEnd message
  372. * },
  373. * error(message) {
  374. * // Handle error message
  375. * },
  376. * });
  377. * ```
  378. * @since v19.9.0
  379. * @experimental
  380. * @param subscribers Set of `TracingChannel Channels` subscribers
  381. */
  382. subscribe(subscribers: TracingChannelSubscribers<ContextType>): void;
  383. /**
  384. * Helper to unsubscribe a collection of functions from the corresponding channels.
  385. * This is the same as calling `channel.unsubscribe(onMessage)` on each channel
  386. * individually.
  387. *
  388. * ```js
  389. * import diagnostics_channel from 'node:diagnostics_channel';
  390. *
  391. * const channels = diagnostics_channel.tracingChannel('my-channel');
  392. *
  393. * channels.unsubscribe({
  394. * start(message) {
  395. * // Handle start message
  396. * },
  397. * end(message) {
  398. * // Handle end message
  399. * },
  400. * asyncStart(message) {
  401. * // Handle asyncStart message
  402. * },
  403. * asyncEnd(message) {
  404. * // Handle asyncEnd message
  405. * },
  406. * error(message) {
  407. * // Handle error message
  408. * },
  409. * });
  410. * ```
  411. * @since v19.9.0
  412. * @experimental
  413. * @param subscribers Set of `TracingChannel Channels` subscribers
  414. * @return `true` if all handlers were successfully unsubscribed, and `false` otherwise.
  415. */
  416. unsubscribe(subscribers: TracingChannelSubscribers<ContextType>): void;
  417. /**
  418. * Trace a synchronous function call. This will always produce a `start event` and `end event` around the execution and may produce an `error event` if the given function throws an error.
  419. * This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  420. * events should have any bound stores set to match this trace context.
  421. *
  422. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  423. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  424. *
  425. * ```js
  426. * import diagnostics_channel from 'node:diagnostics_channel';
  427. *
  428. * const channels = diagnostics_channel.tracingChannel('my-channel');
  429. *
  430. * channels.traceSync(() => {
  431. * // Do something
  432. * }, {
  433. * some: 'thing',
  434. * });
  435. * ```
  436. * @since v19.9.0
  437. * @experimental
  438. * @param fn Function to wrap a trace around
  439. * @param context Shared object to correlate events through
  440. * @param thisArg The receiver to be used for the function call
  441. * @param args Optional arguments to pass to the function
  442. * @return The return value of the given function
  443. */
  444. traceSync<ThisArg = any, Args extends any[] = any[]>(
  445. fn: (this: ThisArg, ...args: Args) => any,
  446. context?: ContextType,
  447. thisArg?: ThisArg,
  448. ...args: Args
  449. ): void;
  450. /**
  451. * Trace a promise-returning function call. This will always produce a `start event` and `end event` around the synchronous portion of the
  452. * function execution, and will produce an `asyncStart event` and `asyncEnd event` when a promise continuation is reached. It may also
  453. * produce an `error event` if the given function throws an error or the
  454. * returned promise rejects. This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  455. * events should have any bound stores set to match this trace context.
  456. *
  457. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  458. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  459. *
  460. * ```js
  461. * import diagnostics_channel from 'node:diagnostics_channel';
  462. *
  463. * const channels = diagnostics_channel.tracingChannel('my-channel');
  464. *
  465. * channels.tracePromise(async () => {
  466. * // Do something
  467. * }, {
  468. * some: 'thing',
  469. * });
  470. * ```
  471. * @since v19.9.0
  472. * @experimental
  473. * @param fn Promise-returning function to wrap a trace around
  474. * @param context Shared object to correlate trace events through
  475. * @param thisArg The receiver to be used for the function call
  476. * @param args Optional arguments to pass to the function
  477. * @return Chained from promise returned by the given function
  478. */
  479. tracePromise<ThisArg = any, Args extends any[] = any[]>(
  480. fn: (this: ThisArg, ...args: Args) => Promise<any>,
  481. context?: ContextType,
  482. thisArg?: ThisArg,
  483. ...args: Args
  484. ): void;
  485. /**
  486. * Trace a callback-receiving function call. This will always produce a `start event` and `end event` around the synchronous portion of the
  487. * function execution, and will produce a `asyncStart event` and `asyncEnd event` around the callback execution. It may also produce an `error event` if the given function throws an error or
  488. * the returned
  489. * promise rejects. This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  490. * events should have any bound stores set to match this trace context.
  491. *
  492. * The `position` will be -1 by default to indicate the final argument should
  493. * be used as the callback.
  494. *
  495. * ```js
  496. * import diagnostics_channel from 'node:diagnostics_channel';
  497. *
  498. * const channels = diagnostics_channel.tracingChannel('my-channel');
  499. *
  500. * channels.traceCallback((arg1, callback) => {
  501. * // Do something
  502. * callback(null, 'result');
  503. * }, 1, {
  504. * some: 'thing',
  505. * }, thisArg, arg1, callback);
  506. * ```
  507. *
  508. * The callback will also be run with `channel.runStores(context, ...)` which
  509. * enables context loss recovery in some cases.
  510. *
  511. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  512. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  513. *
  514. * ```js
  515. * import diagnostics_channel from 'node:diagnostics_channel';
  516. * import { AsyncLocalStorage } from 'node:async_hooks';
  517. *
  518. * const channels = diagnostics_channel.tracingChannel('my-channel');
  519. * const myStore = new AsyncLocalStorage();
  520. *
  521. * // The start channel sets the initial store data to something
  522. * // and stores that store data value on the trace context object
  523. * channels.start.bindStore(myStore, (data) => {
  524. * const span = new Span(data);
  525. * data.span = span;
  526. * return span;
  527. * });
  528. *
  529. * // Then asyncStart can restore from that data it stored previously
  530. * channels.asyncStart.bindStore(myStore, (data) => {
  531. * return data.span;
  532. * });
  533. * ```
  534. * @since v19.9.0
  535. * @experimental
  536. * @param fn callback using function to wrap a trace around
  537. * @param position Zero-indexed argument position of expected callback
  538. * @param context Shared object to correlate trace events through
  539. * @param thisArg The receiver to be used for the function call
  540. * @param args Optional arguments to pass to the function
  541. * @return The return value of the given function
  542. */
  543. traceCallback<Fn extends (this: any, ...args: any[]) => any>(
  544. fn: Fn,
  545. position?: number,
  546. context?: ContextType,
  547. thisArg?: any,
  548. ...args: Parameters<Fn>
  549. ): void;
  550. /**
  551. * `true` if any of the individual channels has a subscriber, `false` if not.
  552. *
  553. * This is a helper method available on a {@link TracingChannel} instance to check
  554. * if any of the [TracingChannel Channels](https://nodejs.org/api/diagnostics_channel.html#tracingchannel-channels) have subscribers.
  555. * A `true` is returned if any of them have at least one subscriber, a `false` is returned otherwise.
  556. *
  557. * ```js
  558. * const diagnostics_channel = require('node:diagnostics_channel');
  559. *
  560. * const channels = diagnostics_channel.tracingChannel('my-channel');
  561. *
  562. * if (channels.hasSubscribers) {
  563. * // Do something
  564. * }
  565. * ```
  566. * @since v22.0.0, v20.13.0
  567. */
  568. readonly hasSubscribers: boolean;
  569. }
  570. }
  571. declare module "node:diagnostics_channel" {
  572. export * from "diagnostics_channel";
  573. }