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