1# Diagnostics Channel 2 3<!-- YAML 4added: 5 - v15.1.0 6 - v14.17.0 7changes: 8 - version: v18.13.0 9 pr-url: https://github.com/nodejs/node/pull/45290 10 description: diagnostics_channel is now Stable. 11--> 12 13<!--introduced_in=v15.1.0--> 14 15> Stability: 2 - Stable 16 17<!-- source_link=lib/diagnostics_channel.js --> 18 19The `node:diagnostics_channel` module provides an API to create named channels 20to report arbitrary message data for diagnostics purposes. 21 22It can be accessed using: 23 24```mjs 25import diagnostics_channel from 'node:diagnostics_channel'; 26``` 27 28```cjs 29const diagnostics_channel = require('node:diagnostics_channel'); 30``` 31 32It is intended that a module writer wanting to report diagnostics messages 33will create one or many top-level channels to report messages through. 34Channels may also be acquired at runtime but it is not encouraged 35due to the additional overhead of doing so. Channels may be exported for 36convenience, but as long as the name is known it can be acquired anywhere. 37 38If you intend for your module to produce diagnostics data for others to 39consume it is recommended that you include documentation of what named 40channels are used along with the shape of the message data. Channel names 41should generally include the module name to avoid collisions with data from 42other modules. 43 44## Public API 45 46### Overview 47 48Following is a simple overview of the public API. 49 50```mjs 51import diagnostics_channel from 'node:diagnostics_channel'; 52 53// Get a reusable channel object 54const channel = diagnostics_channel.channel('my-channel'); 55 56function onMessage(message, name) { 57 // Received data 58} 59 60// Subscribe to the channel 61diagnostics_channel.subscribe('my-channel', onMessage); 62 63// Check if the channel has an active subscriber 64if (channel.hasSubscribers) { 65 // Publish data to the channel 66 channel.publish({ 67 some: 'data', 68 }); 69} 70 71// Unsubscribe from the channel 72diagnostics_channel.unsubscribe('my-channel', onMessage); 73``` 74 75```cjs 76const diagnostics_channel = require('node:diagnostics_channel'); 77 78// Get a reusable channel object 79const channel = diagnostics_channel.channel('my-channel'); 80 81function onMessage(message, name) { 82 // Received data 83} 84 85// Subscribe to the channel 86diagnostics_channel.subscribe('my-channel', onMessage); 87 88// Check if the channel has an active subscriber 89if (channel.hasSubscribers) { 90 // Publish data to the channel 91 channel.publish({ 92 some: 'data', 93 }); 94} 95 96// Unsubscribe from the channel 97diagnostics_channel.unsubscribe('my-channel', onMessage); 98``` 99 100#### `diagnostics_channel.hasSubscribers(name)` 101 102<!-- YAML 103added: 104 - v15.1.0 105 - v14.17.0 106--> 107 108* `name` {string|symbol} The channel name 109* Returns: {boolean} If there are active subscribers 110 111Check if there are active subscribers to the named channel. This is helpful if 112the message you want to send might be expensive to prepare. 113 114This API is optional but helpful when trying to publish messages from very 115performance-sensitive code. 116 117```mjs 118import diagnostics_channel from 'node:diagnostics_channel'; 119 120if (diagnostics_channel.hasSubscribers('my-channel')) { 121 // There are subscribers, prepare and publish message 122} 123``` 124 125```cjs 126const diagnostics_channel = require('node:diagnostics_channel'); 127 128if (diagnostics_channel.hasSubscribers('my-channel')) { 129 // There are subscribers, prepare and publish message 130} 131``` 132 133#### `diagnostics_channel.channel(name)` 134 135<!-- YAML 136added: 137 - v15.1.0 138 - v14.17.0 139--> 140 141* `name` {string|symbol} The channel name 142* Returns: {Channel} The named channel object 143 144This is the primary entry-point for anyone wanting to publish to a named 145channel. It produces a channel object which is optimized to reduce overhead at 146publish time as much as possible. 147 148```mjs 149import diagnostics_channel from 'node:diagnostics_channel'; 150 151const channel = diagnostics_channel.channel('my-channel'); 152``` 153 154```cjs 155const diagnostics_channel = require('node:diagnostics_channel'); 156 157const channel = diagnostics_channel.channel('my-channel'); 158``` 159 160#### `diagnostics_channel.subscribe(name, onMessage)` 161 162<!-- YAML 163added: 164 - v18.7.0 165--> 166 167* `name` {string|symbol} The channel name 168* `onMessage` {Function} The handler to receive channel messages 169 * `message` {any} The message data 170 * `name` {string|symbol} The name of the channel 171 172Register a message handler to subscribe to this channel. This message handler 173will be run synchronously whenever a message is published to the channel. Any 174errors thrown in the message handler will trigger an [`'uncaughtException'`][]. 175 176```mjs 177import diagnostics_channel from 'node:diagnostics_channel'; 178 179diagnostics_channel.subscribe('my-channel', (message, name) => { 180 // Received data 181}); 182``` 183 184```cjs 185const diagnostics_channel = require('node:diagnostics_channel'); 186 187diagnostics_channel.subscribe('my-channel', (message, name) => { 188 // Received data 189}); 190``` 191 192#### `diagnostics_channel.unsubscribe(name, onMessage)` 193 194<!-- YAML 195added: 196 - v18.7.0 197--> 198 199* `name` {string|symbol} The channel name 200* `onMessage` {Function} The previous subscribed handler to remove 201* Returns: {boolean} `true` if the handler was found, `false` otherwise. 202 203Remove a message handler previously registered to this channel with 204[`diagnostics_channel.subscribe(name, onMessage)`][]. 205 206```mjs 207import diagnostics_channel from 'node:diagnostics_channel'; 208 209function onMessage(message, name) { 210 // Received data 211} 212 213diagnostics_channel.subscribe('my-channel', onMessage); 214 215diagnostics_channel.unsubscribe('my-channel', onMessage); 216``` 217 218```cjs 219const diagnostics_channel = require('node:diagnostics_channel'); 220 221function onMessage(message, name) { 222 // Received data 223} 224 225diagnostics_channel.subscribe('my-channel', onMessage); 226 227diagnostics_channel.unsubscribe('my-channel', onMessage); 228``` 229 230#### `diagnostics_channel.tracingChannel(nameOrChannels)` 231 232<!-- YAML 233added: 234 - v18.19.0 235--> 236 237> Stability: 1 - Experimental 238 239* `nameOrChannels` {string|TracingChannel} Channel name or 240 object containing all the [TracingChannel Channels][] 241* Returns: {TracingChannel} Collection of channels to trace with 242 243Creates a [`TracingChannel`][] wrapper for the given 244[TracingChannel Channels][]. If a name is given, the corresponding tracing 245channels will be created in the form of `tracing:${name}:${eventType}` where 246`eventType` corresponds to the types of [TracingChannel Channels][]. 247 248```mjs 249import diagnostics_channel from 'node:diagnostics_channel'; 250 251const channelsByName = diagnostics_channel.tracingChannel('my-channel'); 252 253// or... 254 255const channelsByCollection = diagnostics_channel.tracingChannel({ 256 start: diagnostics_channel.channel('tracing:my-channel:start'), 257 end: diagnostics_channel.channel('tracing:my-channel:end'), 258 asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'), 259 asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'), 260 error: diagnostics_channel.channel('tracing:my-channel:error'), 261}); 262``` 263 264```cjs 265const diagnostics_channel = require('node:diagnostics_channel'); 266 267const channelsByName = diagnostics_channel.tracingChannel('my-channel'); 268 269// or... 270 271const channelsByCollection = diagnostics_channel.tracingChannel({ 272 start: diagnostics_channel.channel('tracing:my-channel:start'), 273 end: diagnostics_channel.channel('tracing:my-channel:end'), 274 asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'), 275 asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'), 276 error: diagnostics_channel.channel('tracing:my-channel:error'), 277}); 278``` 279 280### Class: `Channel` 281 282<!-- YAML 283added: 284 - v15.1.0 285 - v14.17.0 286--> 287 288The class `Channel` represents an individual named channel within the data 289pipeline. It is used to track subscribers and to publish messages when there 290are subscribers present. It exists as a separate object to avoid channel 291lookups at publish time, enabling very fast publish speeds and allowing 292for heavy use while incurring very minimal cost. Channels are created with 293[`diagnostics_channel.channel(name)`][], constructing a channel directly 294with `new Channel(name)` is not supported. 295 296#### `channel.hasSubscribers` 297 298<!-- YAML 299added: 300 - v15.1.0 301 - v14.17.0 302--> 303 304* Returns: {boolean} If there are active subscribers 305 306Check if there are active subscribers to this channel. This is helpful if 307the message you want to send might be expensive to prepare. 308 309This API is optional but helpful when trying to publish messages from very 310performance-sensitive code. 311 312```mjs 313import diagnostics_channel from 'node:diagnostics_channel'; 314 315const channel = diagnostics_channel.channel('my-channel'); 316 317if (channel.hasSubscribers) { 318 // There are subscribers, prepare and publish message 319} 320``` 321 322```cjs 323const diagnostics_channel = require('node:diagnostics_channel'); 324 325const channel = diagnostics_channel.channel('my-channel'); 326 327if (channel.hasSubscribers) { 328 // There are subscribers, prepare and publish message 329} 330``` 331 332#### `channel.publish(message)` 333 334<!-- YAML 335added: 336 - v15.1.0 337 - v14.17.0 338--> 339 340* `message` {any} The message to send to the channel subscribers 341 342Publish a message to any subscribers to the channel. This will trigger 343message handlers synchronously so they will execute within the same context. 344 345```mjs 346import diagnostics_channel from 'node:diagnostics_channel'; 347 348const channel = diagnostics_channel.channel('my-channel'); 349 350channel.publish({ 351 some: 'message', 352}); 353``` 354 355```cjs 356const diagnostics_channel = require('node:diagnostics_channel'); 357 358const channel = diagnostics_channel.channel('my-channel'); 359 360channel.publish({ 361 some: 'message', 362}); 363``` 364 365#### `channel.subscribe(onMessage)` 366 367<!-- YAML 368added: 369 - v15.1.0 370 - v14.17.0 371deprecated: v18.7.0 372--> 373 374> Stability: 0 - Deprecated: Use [`diagnostics_channel.subscribe(name, onMessage)`][] 375 376* `onMessage` {Function} The handler to receive channel messages 377 * `message` {any} The message data 378 * `name` {string|symbol} The name of the channel 379 380Register a message handler to subscribe to this channel. This message handler 381will be run synchronously whenever a message is published to the channel. Any 382errors thrown in the message handler will trigger an [`'uncaughtException'`][]. 383 384```mjs 385import diagnostics_channel from 'node:diagnostics_channel'; 386 387const channel = diagnostics_channel.channel('my-channel'); 388 389channel.subscribe((message, name) => { 390 // Received data 391}); 392``` 393 394```cjs 395const diagnostics_channel = require('node:diagnostics_channel'); 396 397const channel = diagnostics_channel.channel('my-channel'); 398 399channel.subscribe((message, name) => { 400 // Received data 401}); 402``` 403 404#### `channel.unsubscribe(onMessage)` 405 406<!-- YAML 407added: 408 - v15.1.0 409 - v14.17.0 410deprecated: v18.7.0 411changes: 412 - version: 413 - v17.1.0 414 - v16.14.0 415 - v14.19.0 416 pr-url: https://github.com/nodejs/node/pull/40433 417 description: Added return value. Added to channels without subscribers. 418--> 419 420> Stability: 0 - Deprecated: Use [`diagnostics_channel.unsubscribe(name, onMessage)`][] 421 422* `onMessage` {Function} The previous subscribed handler to remove 423* Returns: {boolean} `true` if the handler was found, `false` otherwise. 424 425Remove a message handler previously registered to this channel with 426[`channel.subscribe(onMessage)`][]. 427 428```mjs 429import diagnostics_channel from 'node:diagnostics_channel'; 430 431const channel = diagnostics_channel.channel('my-channel'); 432 433function onMessage(message, name) { 434 // Received data 435} 436 437channel.subscribe(onMessage); 438 439channel.unsubscribe(onMessage); 440``` 441 442```cjs 443const diagnostics_channel = require('node:diagnostics_channel'); 444 445const channel = diagnostics_channel.channel('my-channel'); 446 447function onMessage(message, name) { 448 // Received data 449} 450 451channel.subscribe(onMessage); 452 453channel.unsubscribe(onMessage); 454``` 455 456#### `channel.bindStore(store[, transform])` 457 458<!-- YAML 459added: 460 - v18.19.0 461--> 462 463> Stability: 1 - Experimental 464 465* `store` {AsyncLocalStorage} The store to which to bind the context data 466* `transform` {Function} Transform context data before setting the store context 467 468When [`channel.runStores(context, ...)`][] is called, the given context data 469will be applied to any store bound to the channel. If the store has already been 470bound the previous `transform` function will be replaced with the new one. 471The `transform` function may be omitted to set the given context data as the 472context directly. 473 474```mjs 475import diagnostics_channel from 'node:diagnostics_channel'; 476import { AsyncLocalStorage } from 'node:async_hooks'; 477 478const store = new AsyncLocalStorage(); 479 480const channel = diagnostics_channel.channel('my-channel'); 481 482channel.bindStore(store, (data) => { 483 return { data }; 484}); 485``` 486 487```cjs 488const diagnostics_channel = require('node:diagnostics_channel'); 489const { AsyncLocalStorage } = require('node:async_hooks'); 490 491const store = new AsyncLocalStorage(); 492 493const channel = diagnostics_channel.channel('my-channel'); 494 495channel.bindStore(store, (data) => { 496 return { data }; 497}); 498``` 499 500#### `channel.unbindStore(store)` 501 502<!-- YAML 503added: 504 - v18.19.0 505--> 506 507> Stability: 1 - Experimental 508 509* `store` {AsyncLocalStorage} The store to unbind from the channel. 510* Returns: {boolean} `true` if the store was found, `false` otherwise. 511 512Remove a message handler previously registered to this channel with 513[`channel.bindStore(store)`][]. 514 515```mjs 516import diagnostics_channel from 'node:diagnostics_channel'; 517import { AsyncLocalStorage } from 'node:async_hooks'; 518 519const store = new AsyncLocalStorage(); 520 521const channel = diagnostics_channel.channel('my-channel'); 522 523channel.bindStore(store); 524channel.unbindStore(store); 525``` 526 527```cjs 528const diagnostics_channel = require('node:diagnostics_channel'); 529const { AsyncLocalStorage } = require('node:async_hooks'); 530 531const store = new AsyncLocalStorage(); 532 533const channel = diagnostics_channel.channel('my-channel'); 534 535channel.bindStore(store); 536channel.unbindStore(store); 537``` 538 539#### `channel.runStores(context, fn[, thisArg[, ...args]])` 540 541<!-- YAML 542added: 543 - v18.19.0 544--> 545 546> Stability: 1 - Experimental 547 548* `context` {any} Message to send to subscribers and bind to stores 549* `fn` {Function} Handler to run within the entered storage context 550* `thisArg` {any} The receiver to be used for the function call. 551* `...args` {any} Optional arguments to pass to the function. 552 553Applies the given data to any AsyncLocalStorage instances bound to the channel 554for the duration of the given function, then publishes to the channel within 555the scope of that data is applied to the stores. 556 557If a transform function was given to [`channel.bindStore(store)`][] it will be 558applied to transform the message data before it becomes the context value for 559the store. The prior storage context is accessible from within the transform 560function in cases where context linking is required. 561 562The context applied to the store should be accesible in any async code which 563continues from execution which began during the given function, however 564there are some situations in which [context loss][] may occur. 565 566```mjs 567import diagnostics_channel from 'node:diagnostics_channel'; 568import { AsyncLocalStorage } from 'node:async_hooks'; 569 570const store = new AsyncLocalStorage(); 571 572const channel = diagnostics_channel.channel('my-channel'); 573 574channel.bindStore(store, (message) => { 575 const parent = store.getStore(); 576 return new Span(message, parent); 577}); 578channel.runStores({ some: 'message' }, () => { 579 store.getStore(); // Span({ some: 'message' }) 580}); 581``` 582 583```cjs 584const diagnostics_channel = require('node:diagnostics_channel'); 585const { AsyncLocalStorage } = require('node:async_hooks'); 586 587const store = new AsyncLocalStorage(); 588 589const channel = diagnostics_channel.channel('my-channel'); 590 591channel.bindStore(store, (message) => { 592 const parent = store.getStore(); 593 return new Span(message, parent); 594}); 595channel.runStores({ some: 'message' }, () => { 596 store.getStore(); // Span({ some: 'message' }) 597}); 598``` 599 600### Class: `TracingChannel` 601 602<!-- YAML 603added: 604 - v18.19.0 605--> 606 607> Stability: 1 - Experimental 608 609The class `TracingChannel` is a collection of [TracingChannel Channels][] which 610together express a single traceable action. It is used to formalize and 611simplify the process of producing events for tracing application flow. 612[`diagnostics_channel.tracingChannel()`][] is used to construct a 613`TracingChannel`. As with `Channel` it is recommended to create and reuse a 614single `TracingChannel` at the top-level of the file rather than creating them 615dynamically. 616 617#### `tracingChannel.subscribe(subscribers)` 618 619<!-- YAML 620added: 621 - v18.19.0 622--> 623 624> Stability: 1 - Experimental 625 626* `subscribers` {Object} Set of [TracingChannel Channels][] subscribers 627 * `start` {Function} The [`start` event][] subscriber 628 * `end` {Function} The [`end` event][] subscriber 629 * `asyncStart` {Function} The [`asyncStart` event][] subscriber 630 * `asyncEnd` {Function} The [`asyncEnd` event][] subscriber 631 * `error` {Function} The [`error` event][] subscriber 632 633Helper to subscribe a collection of functions to the corresponding channels. 634This is the same as calling [`channel.subscribe(onMessage)`][] on each channel 635individually. 636 637```mjs 638import diagnostics_channel from 'node:diagnostics_channel'; 639 640const channels = diagnostics_channel.tracingChannel('my-channel'); 641 642channels.subscribe({ 643 start(message) { 644 // Handle start message 645 }, 646 end(message) { 647 // Handle end message 648 }, 649 asyncStart(message) { 650 // Handle asyncStart message 651 }, 652 asyncEnd(message) { 653 // Handle asyncEnd message 654 }, 655 error(message) { 656 // Handle error message 657 }, 658}); 659``` 660 661```cjs 662const diagnostics_channel = require('node:diagnostics_channel'); 663 664const channels = diagnostics_channel.tracingChannel('my-channel'); 665 666channels.subscribe({ 667 start(message) { 668 // Handle start message 669 }, 670 end(message) { 671 // Handle end message 672 }, 673 asyncStart(message) { 674 // Handle asyncStart message 675 }, 676 asyncEnd(message) { 677 // Handle asyncEnd message 678 }, 679 error(message) { 680 // Handle error message 681 }, 682}); 683``` 684 685#### `tracingChannel.unsubscribe(subscribers)` 686 687<!-- YAML 688added: 689 - v18.19.0 690--> 691 692> Stability: 1 - Experimental 693 694* `subscribers` {Object} Set of [TracingChannel Channels][] subscribers 695 * `start` {Function} The [`start` event][] subscriber 696 * `end` {Function} The [`end` event][] subscriber 697 * `asyncStart` {Function} The [`asyncStart` event][] subscriber 698 * `asyncEnd` {Function} The [`asyncEnd` event][] subscriber 699 * `error` {Function} The [`error` event][] subscriber 700* Returns: {boolean} `true` if all handlers were successfully unsubscribed, 701 and `false` otherwise. 702 703Helper to unsubscribe a collection of functions from the corresponding channels. 704This is the same as calling [`channel.unsubscribe(onMessage)`][] on each channel 705individually. 706 707```mjs 708import diagnostics_channel from 'node:diagnostics_channel'; 709 710const channels = diagnostics_channel.tracingChannel('my-channel'); 711 712channels.unsubscribe({ 713 start(message) { 714 // Handle start message 715 }, 716 end(message) { 717 // Handle end message 718 }, 719 asyncStart(message) { 720 // Handle asyncStart message 721 }, 722 asyncEnd(message) { 723 // Handle asyncEnd message 724 }, 725 error(message) { 726 // Handle error message 727 }, 728}); 729``` 730 731```cjs 732const diagnostics_channel = require('node:diagnostics_channel'); 733 734const channels = diagnostics_channel.tracingChannel('my-channel'); 735 736channels.unsubscribe({ 737 start(message) { 738 // Handle start message 739 }, 740 end(message) { 741 // Handle end message 742 }, 743 asyncStart(message) { 744 // Handle asyncStart message 745 }, 746 asyncEnd(message) { 747 // Handle asyncEnd message 748 }, 749 error(message) { 750 // Handle error message 751 }, 752}); 753``` 754 755#### `tracingChannel.traceSync(fn[, context[, thisArg[, ...args]]])` 756 757<!-- YAML 758added: 759 - v18.19.0 760--> 761 762> Stability: 1 - Experimental 763 764* `fn` {Function} Function to wrap a trace around 765* `context` {Object} Shared object to correlate events through 766* `thisArg` {any} The receiver to be used for the function call 767* `...args` {any} Optional arguments to pass to the function 768* Returns: {any} The return value of the given function 769 770Trace a synchronous function call. This will always produce a [`start` event][] 771and [`end` event][] around the execution and may produce an [`error` event][] 772if the given function throws an error. This will run the given function using 773[`channel.runStores(context, ...)`][] on the `start` channel which ensures all 774events should have any bound stores set to match this trace context. 775 776```mjs 777import diagnostics_channel from 'node:diagnostics_channel'; 778 779const channels = diagnostics_channel.tracingChannel('my-channel'); 780 781channels.traceSync(() => { 782 // Do something 783}, { 784 some: 'thing', 785}); 786``` 787 788```cjs 789const diagnostics_channel = require('node:diagnostics_channel'); 790 791const channels = diagnostics_channel.tracingChannel('my-channel'); 792 793channels.traceSync(() => { 794 // Do something 795}, { 796 some: 'thing', 797}); 798``` 799 800#### `tracingChannel.tracePromise(fn[, context[, thisArg[, ...args]]])` 801 802<!-- YAML 803added: 804 - v18.19.0 805--> 806 807> Stability: 1 - Experimental 808 809* `fn` {Function} Promise-returning function to wrap a trace around 810* `context` {Object} Shared object to correlate trace events through 811* `thisArg` {any} The receiver to be used for the function call 812* `...args` {any} Optional arguments to pass to the function 813* Returns: {Promise} Chained from promise returned by the given function 814 815Trace a promise-returning function call. This will always produce a 816[`start` event][] and [`end` event][] around the synchronous portion of the 817function execution, and will produce an [`asyncStart` event][] and 818[`asyncEnd` event][] when a promise continuation is reached. It may also 819produce an [`error` event][] if the given function throws an error or the 820returned promise rejects. This will run the given function using 821[`channel.runStores(context, ...)`][] on the `start` channel which ensures all 822events should have any bound stores set to match this trace context. 823 824```mjs 825import diagnostics_channel from 'node:diagnostics_channel'; 826 827const channels = diagnostics_channel.tracingChannel('my-channel'); 828 829channels.tracePromise(async () => { 830 // Do something 831}, { 832 some: 'thing', 833}); 834``` 835 836```cjs 837const diagnostics_channel = require('node:diagnostics_channel'); 838 839const channels = diagnostics_channel.tracingChannel('my-channel'); 840 841channels.tracePromise(async () => { 842 // Do something 843}, { 844 some: 'thing', 845}); 846``` 847 848#### `tracingChannel.traceCallback(fn[, position[, context[, thisArg[, ...args]]]])` 849 850<!-- YAML 851added: 852 - v18.19.0 853--> 854 855> Stability: 1 - Experimental 856 857* `fn` {Function} callback using function to wrap a trace around 858* `position` {number} Zero-indexed argument position of expected callback 859* `context` {Object} Shared object to correlate trace events through 860* `thisArg` {any} The receiver to be used for the function call 861* `...args` {any} Optional arguments to pass to the function 862* Returns: {any} The return value of the given function 863 864Trace a callback-receiving function call. This will always produce a 865[`start` event][] and [`end` event][] around the synchronous portion of the 866function execution, and will produce a [`asyncStart` event][] and 867[`asyncEnd` event][] around the callback execution. It may also produce an 868[`error` event][] if the given function throws an error or the returned 869promise rejects. This will run the given function using 870[`channel.runStores(context, ...)`][] on the `start` channel which ensures all 871events should have any bound stores set to match this trace context. 872 873The `position` will be -1 by default to indicate the final argument should 874be used as the callback. 875 876```mjs 877import diagnostics_channel from 'node:diagnostics_channel'; 878 879const channels = diagnostics_channel.tracingChannel('my-channel'); 880 881channels.traceCallback((arg1, callback) => { 882 // Do something 883 callback(null, 'result'); 884}, 1, { 885 some: 'thing', 886}, thisArg, arg1, callback); 887``` 888 889```cjs 890const diagnostics_channel = require('node:diagnostics_channel'); 891 892const channels = diagnostics_channel.tracingChannel('my-channel'); 893 894channels.traceCallback((arg1, callback) => { 895 // Do something 896 callback(null, 'result'); 897}, { 898 some: 'thing', 899}, thisArg, arg1, callback); 900``` 901 902The callback will also be run with [`channel.runStores(context, ...)`][] which 903enables context loss recovery in some cases. 904 905```mjs 906import diagnostics_channel from 'node:diagnostics_channel'; 907import { AsyncLocalStorage } from 'node:async_hooks'; 908 909const channels = diagnostics_channel.tracingChannel('my-channel'); 910const myStore = new AsyncLocalStorage(); 911 912// The start channel sets the initial store data to something 913// and stores that store data value on the trace context object 914channels.start.bindStore(myStore, (data) => { 915 const span = new Span(data); 916 data.span = span; 917 return span; 918}); 919 920// Then asyncStart can restore from that data it stored previously 921channels.asyncStart.bindStore(myStore, (data) => { 922 return data.span; 923}); 924``` 925 926```cjs 927const diagnostics_channel = require('node:diagnostics_channel'); 928const { AsyncLocalStorage } = require('node:async_hooks'); 929 930const channels = diagnostics_channel.tracingChannel('my-channel'); 931const myStore = new AsyncLocalStorage(); 932 933// The start channel sets the initial store data to something 934// and stores that store data value on the trace context object 935channels.start.bindStore(myStore, (data) => { 936 const span = new Span(data); 937 data.span = span; 938 return span; 939}); 940 941// Then asyncStart can restore from that data it stored previously 942channels.asyncStart.bindStore(myStore, (data) => { 943 return data.span; 944}); 945``` 946 947### TracingChannel Channels 948 949A TracingChannel is a collection of several diagnostics\_channels representing 950specific points in the execution lifecycle of a single traceable action. The 951behaviour is split into five diagnostics\_channels consisting of `start`, 952`end`, `asyncStart`, `asyncEnd`, and `error`. A single traceable action will 953share the same event object between all events, this can be helpful for 954managing correlation through a weakmap. 955 956These event objects will be extended with `result` or `error` values when 957the task "completes". In the case of a synchronous task the `result` will be 958the return value and the `error` will be anything thrown from the function. 959With callback-based async functions the `result` will be the second argument 960of the callback while the `error` will either be a thrown error visible in the 961`end` event or the first callback argument in either of the `asyncStart` or 962`asyncEnd` events. 963 964Tracing channels should follow a naming pattern of: 965 966* `tracing:module.class.method:start` or `tracing:module.function:start` 967* `tracing:module.class.method:end` or `tracing:module.function:end` 968* `tracing:module.class.method:asyncStart` or `tracing:module.function:asyncStart` 969* `tracing:module.class.method:asyncEnd` or `tracing:module.function:asyncEnd` 970* `tracing:module.class.method:error` or `tracing:module.function:error` 971 972#### `start(event)` 973 974* Name: `tracing:${name}:start` 975 976The `start` event represents the point at which a function is called. At this 977point the event data may contain function arguments or anything else available 978at the very start of the execution of the function. 979 980#### `end(event)` 981 982* Name: `tracing:${name}:end` 983 984The `end` event represents the point at which a function call returns a value. 985In the case of an async function this is when the promise returned not when the 986function itself makes a return statement internally. At this point, if the 987traced function was synchronous the `result` field will be set to the return 988value of the function. Alternatively, the `error` field may be present to 989represent any thrown errors. 990 991It is recommended to listen specifically to the `error` event to track errors 992as it may be possible for a traceable action to produce multiple errors. For 993example, an async task which fails may be started internally before the sync 994part of the task then throws an error. 995 996#### `asyncStart(event)` 997 998* Name: `tracing:${name}:asyncStart` 999 1000The `asyncStart` event represents the callback or continuation of a traceable 1001function being reached. At this point things like callback arguments may be 1002available, or anything else expressing the "result" of the action. 1003 1004For callbacks-based functions, the first argument of the callback will be 1005assigned to the `error` field, if not `undefined` or `null`, and the second 1006argument will be assigned to the `result` field. 1007 1008For promises, the argument to the `resolve` path will be assigned to `result` 1009or the argument to the `reject` path will be assign to `error`. 1010 1011It is recommended to listen specifically to the `error` event to track errors 1012as it may be possible for a traceable action to produce multiple errors. For 1013example, an async task which fails may be started internally before the sync 1014part of the task then throws an error. 1015 1016#### `asyncEnd(event)` 1017 1018* Name: `tracing:${name}:asyncEnd` 1019 1020The `asyncEnd` event represents the callback of an asynchronous function 1021returning. It's not likely event data will change after the `asyncStart` event, 1022however it may be useful to see the point where the callback completes. 1023 1024#### `error(event)` 1025 1026* Name: `tracing:${name}:error` 1027 1028The `error` event represents any error produced by the traceable function 1029either synchronously or asynchronously. If an error is thrown in the 1030synchronous portion of the traced function the error will be assigned to the 1031`error` field of the event and the `error` event will be triggered. If an error 1032is received asynchronously through a callback or promise rejection it will also 1033be assigned to the `error` field of the event and trigger the `error` event. 1034 1035It is possible for a single traceable function call to produce errors multiple 1036times so this should be considered when consuming this event. For example, if 1037another async task is triggered internally which fails and then the sync part 1038of the function then throws and error two `error` events will be emitted, one 1039for the sync error and one for the async error. 1040 1041### Built-in Channels 1042 1043> Stability: 1 - Experimental 1044 1045While the diagnostics\_channel API is now considered stable, the built-in 1046channels currently available are not. Each channel must be declared stable 1047independently. 1048 1049#### HTTP 1050 1051`http.client.request.start` 1052 1053* `request` {http.ClientRequest} 1054 1055Emitted when client starts a request. 1056 1057`http.client.response.finish` 1058 1059* `request` {http.ClientRequest} 1060* `response` {http.IncomingMessage} 1061 1062Emitted when client receives a response. 1063 1064`http.server.request.start` 1065 1066* `request` {http.IncomingMessage} 1067* `response` {http.ServerResponse} 1068* `socket` {net.Socket} 1069* `server` {http.Server} 1070 1071Emitted when server receives a request. 1072 1073`http.server.response.finish` 1074 1075* `request` {http.IncomingMessage} 1076* `response` {http.ServerResponse} 1077* `socket` {net.Socket} 1078* `server` {http.Server} 1079 1080Emitted when server sends a response. 1081 1082`net.client.socket` 1083 1084* `socket` {net.Socket} 1085 1086Emitted when a new TCP or pipe client socket is created. 1087 1088`net.server.socket` 1089 1090* `socket` {net.Socket} 1091 1092Emitted when a new TCP or pipe connection is received. 1093 1094`udp.socket` 1095 1096* `socket` {dgram.Socket} 1097 1098Emitted when a new UDP socket is created. 1099 1100[TracingChannel Channels]: #tracingchannel-channels 1101[`'uncaughtException'`]: process.md#event-uncaughtexception 1102[`TracingChannel`]: #class-tracingchannel 1103[`asyncEnd` event]: #asyncendevent 1104[`asyncStart` event]: #asyncstartevent 1105[`channel.bindStore(store)`]: #channelbindstorestore-transform 1106[`channel.runStores(context, ...)`]: #channelrunstorescontext-fn-thisarg-args 1107[`channel.subscribe(onMessage)`]: #channelsubscribeonmessage 1108[`channel.unsubscribe(onMessage)`]: #channelunsubscribeonmessage 1109[`diagnostics_channel.channel(name)`]: #diagnostics_channelchannelname 1110[`diagnostics_channel.subscribe(name, onMessage)`]: #diagnostics_channelsubscribename-onmessage 1111[`diagnostics_channel.tracingChannel()`]: #diagnostics_channeltracingchannelnameorchannels 1112[`diagnostics_channel.unsubscribe(name, onMessage)`]: #diagnostics_channelunsubscribename-onmessage 1113[`end` event]: #endevent 1114[`error` event]: #errorevent 1115[`start` event]: #startevent 1116[context loss]: async_context.md#troubleshooting-context-loss 1117