0d53d70623467bcf7122f4f997c58cdf742170ef28677b1dbb445b7af4ad037c21ea7362f19a5acdbb709ed2b691b4c94fbfb546b076bfd55e32c3994a5ae7 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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/v24.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<ThisArg = any, Args extends any[] = any[], Result = any>(
  301. context: ContextType,
  302. fn: (this: ThisArg, ...args: Args) => Result,
  303. thisArg?: ThisArg,
  304. ...args: Args
  305. ): Result;
  306. }
  307. interface TracingChannelSubscribers<ContextType extends object> {
  308. start: (message: ContextType) => void;
  309. end: (
  310. message: ContextType & {
  311. error?: unknown;
  312. result?: unknown;
  313. },
  314. ) => void;
  315. asyncStart: (
  316. message: ContextType & {
  317. error?: unknown;
  318. result?: unknown;
  319. },
  320. ) => void;
  321. asyncEnd: (
  322. message: ContextType & {
  323. error?: unknown;
  324. result?: unknown;
  325. },
  326. ) => void;
  327. error: (
  328. message: ContextType & {
  329. error: unknown;
  330. },
  331. ) => void;
  332. }
  333. interface TracingChannelCollection<StoreType = unknown, ContextType = StoreType> {
  334. start: Channel<StoreType, ContextType>;
  335. end: Channel<StoreType, ContextType>;
  336. asyncStart: Channel<StoreType, ContextType>;
  337. asyncEnd: Channel<StoreType, ContextType>;
  338. error: Channel<StoreType, ContextType>;
  339. }
  340. /**
  341. * The class `TracingChannel` is a collection of `TracingChannel Channels` which
  342. * together express a single traceable action. It is used to formalize and
  343. * 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
  344. * single `TracingChannel` at the top-level of the file rather than creating them
  345. * dynamically.
  346. * @since v19.9.0
  347. * @experimental
  348. */
  349. class TracingChannel<StoreType = unknown, ContextType extends object = {}> implements TracingChannelCollection {
  350. start: Channel<StoreType, ContextType>;
  351. end: Channel<StoreType, ContextType>;
  352. asyncStart: Channel<StoreType, ContextType>;
  353. asyncEnd: Channel<StoreType, ContextType>;
  354. error: Channel<StoreType, ContextType>;
  355. /**
  356. * Helper to subscribe a collection of functions to the corresponding channels.
  357. * This is the same as calling `channel.subscribe(onMessage)` on each channel
  358. * individually.
  359. *
  360. * ```js
  361. * import diagnostics_channel from 'node:diagnostics_channel';
  362. *
  363. * const channels = diagnostics_channel.tracingChannel('my-channel');
  364. *
  365. * channels.subscribe({
  366. * start(message) {
  367. * // Handle start message
  368. * },
  369. * end(message) {
  370. * // Handle end message
  371. * },
  372. * asyncStart(message) {
  373. * // Handle asyncStart message
  374. * },
  375. * asyncEnd(message) {
  376. * // Handle asyncEnd message
  377. * },
  378. * error(message) {
  379. * // Handle error message
  380. * },
  381. * });
  382. * ```
  383. * @since v19.9.0
  384. * @experimental
  385. * @param subscribers Set of `TracingChannel Channels` subscribers
  386. */
  387. subscribe(subscribers: TracingChannelSubscribers<ContextType>): void;
  388. /**
  389. * Helper to unsubscribe a collection of functions from the corresponding channels.
  390. * This is the same as calling `channel.unsubscribe(onMessage)` on each channel
  391. * individually.
  392. *
  393. * ```js
  394. * import diagnostics_channel from 'node:diagnostics_channel';
  395. *
  396. * const channels = diagnostics_channel.tracingChannel('my-channel');
  397. *
  398. * channels.unsubscribe({
  399. * start(message) {
  400. * // Handle start message
  401. * },
  402. * end(message) {
  403. * // Handle end message
  404. * },
  405. * asyncStart(message) {
  406. * // Handle asyncStart message
  407. * },
  408. * asyncEnd(message) {
  409. * // Handle asyncEnd message
  410. * },
  411. * error(message) {
  412. * // Handle error message
  413. * },
  414. * });
  415. * ```
  416. * @since v19.9.0
  417. * @experimental
  418. * @param subscribers Set of `TracingChannel Channels` subscribers
  419. * @return `true` if all handlers were successfully unsubscribed, and `false` otherwise.
  420. */
  421. unsubscribe(subscribers: TracingChannelSubscribers<ContextType>): void;
  422. /**
  423. * 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.
  424. * This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  425. * events should have any bound stores set to match this trace context.
  426. *
  427. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  428. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  429. *
  430. * ```js
  431. * import diagnostics_channel from 'node:diagnostics_channel';
  432. *
  433. * const channels = diagnostics_channel.tracingChannel('my-channel');
  434. *
  435. * channels.traceSync(() => {
  436. * // Do something
  437. * }, {
  438. * some: 'thing',
  439. * });
  440. * ```
  441. * @since v19.9.0
  442. * @experimental
  443. * @param fn Function to wrap a trace around
  444. * @param context Shared object to correlate events through
  445. * @param thisArg The receiver to be used for the function call
  446. * @param args Optional arguments to pass to the function
  447. * @return The return value of the given function
  448. */
  449. traceSync<ThisArg = any, Args extends any[] = any[], Result = any>(
  450. fn: (this: ThisArg, ...args: Args) => Result,
  451. context?: ContextType,
  452. thisArg?: ThisArg,
  453. ...args: Args
  454. ): Result;
  455. /**
  456. * Trace a promise-returning function call. This will always produce a `start event` and `end event` around the synchronous portion of the
  457. * function execution, and will produce an `asyncStart event` and `asyncEnd event` when a promise continuation is reached. It may also
  458. * produce an `error event` if the given function throws an error or the
  459. * returned promise rejects. This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  460. * events should have any bound stores set to match this trace context.
  461. *
  462. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  463. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  464. *
  465. * ```js
  466. * import diagnostics_channel from 'node:diagnostics_channel';
  467. *
  468. * const channels = diagnostics_channel.tracingChannel('my-channel');
  469. *
  470. * channels.tracePromise(async () => {
  471. * // Do something
  472. * }, {
  473. * some: 'thing',
  474. * });
  475. * ```
  476. * @since v19.9.0
  477. * @experimental
  478. * @param fn Promise-returning function to wrap a trace around
  479. * @param context Shared object to correlate trace events through
  480. * @param thisArg The receiver to be used for the function call
  481. * @param args Optional arguments to pass to the function
  482. * @return Chained from promise returned by the given function
  483. */
  484. tracePromise<ThisArg = any, Args extends any[] = any[], Result = any>(
  485. fn: (this: ThisArg, ...args: Args) => Promise<Result>,
  486. context?: ContextType,
  487. thisArg?: ThisArg,
  488. ...args: Args
  489. ): Promise<Result>;
  490. /**
  491. * Trace a callback-receiving function call. This will always produce a `start event` and `end event` around the synchronous portion of the
  492. * 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
  493. * the returned
  494. * promise rejects. This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all
  495. * events should have any bound stores set to match this trace context.
  496. *
  497. * The `position` will be -1 by default to indicate the final argument should
  498. * be used as the callback.
  499. *
  500. * ```js
  501. * import diagnostics_channel from 'node:diagnostics_channel';
  502. *
  503. * const channels = diagnostics_channel.tracingChannel('my-channel');
  504. *
  505. * channels.traceCallback((arg1, callback) => {
  506. * // Do something
  507. * callback(null, 'result');
  508. * }, 1, {
  509. * some: 'thing',
  510. * }, thisArg, arg1, callback);
  511. * ```
  512. *
  513. * The callback will also be run with `channel.runStores(context, ...)` which
  514. * enables context loss recovery in some cases.
  515. *
  516. * To ensure only correct trace graphs are formed, events will only be published if subscribers are present prior to starting the trace. Subscriptions
  517. * which are added after the trace begins will not receive future events from that trace, only future traces will be seen.
  518. *
  519. * ```js
  520. * import diagnostics_channel from 'node:diagnostics_channel';
  521. * import { AsyncLocalStorage } from 'node:async_hooks';
  522. *
  523. * const channels = diagnostics_channel.tracingChannel('my-channel');
  524. * const myStore = new AsyncLocalStorage();
  525. *
  526. * // The start channel sets the initial store data to something
  527. * // and stores that store data value on the trace context object
  528. * channels.start.bindStore(myStore, (data) => {
  529. * const span = new Span(data);
  530. * data.span = span;
  531. * return span;
  532. * });
  533. *
  534. * // Then asyncStart can restore from that data it stored previously
  535. * channels.asyncStart.bindStore(myStore, (data) => {
  536. * return data.span;
  537. * });
  538. * ```
  539. * @since v19.9.0
  540. * @experimental
  541. * @param fn callback using function to wrap a trace around
  542. * @param position Zero-indexed argument position of expected callback
  543. * @param context Shared object to correlate trace events through
  544. * @param thisArg The receiver to be used for the function call
  545. * @param args Optional arguments to pass to the function
  546. * @return The return value of the given function
  547. */
  548. traceCallback<ThisArg = any, Args extends any[] = any[], Result = any>(
  549. fn: (this: ThisArg, ...args: Args) => Result,
  550. position?: number,
  551. context?: ContextType,
  552. thisArg?: ThisArg,
  553. ...args: Args
  554. ): Result;
  555. /**
  556. * `true` if any of the individual channels has a subscriber, `false` if not.
  557. *
  558. * This is a helper method available on a {@link TracingChannel} instance to check
  559. * if any of the [TracingChannel Channels](https://nodejs.org/api/diagnostics_channel.html#tracingchannel-channels) have subscribers.
  560. * A `true` is returned if any of them have at least one subscriber, a `false` is returned otherwise.
  561. *
  562. * ```js
  563. * const diagnostics_channel = require('node:diagnostics_channel');
  564. *
  565. * const channels = diagnostics_channel.tracingChannel('my-channel');
  566. *
  567. * if (channels.hasSubscribers) {
  568. * // Do something
  569. * }
  570. * ```
  571. * @since v22.0.0, v20.13.0
  572. */
  573. readonly hasSubscribers: boolean;
  574. }
  575. }
  576. declare module "node:diagnostics_channel" {
  577. export * from "diagnostics_channel";
  578. }