From 68b898ae5653654e70fe4c264c7e443c44e81c00 Mon Sep 17 00:00:00 2001 From: Divyanshu Sharma Date: Thu, 2 Jul 2026 02:32:32 +0530 Subject: [PATCH 1/6] doc: add diagnostics_channel bypass API documentation Signed-off-by: Divyanshu Sharma --- doc/api/diagnostics_channel.md | 176 ++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 3 deletions(-) diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index fb1bf6e93f2948..1b8242861b5465 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -72,6 +72,13 @@ if (channel.hasSubscribers) { // Unsubscribe from the channel diagnostics_channel.unsubscribe('my-channel', onMessage); + +// Use bypass() to skip opted-in subscribers during internal calls +const kMyTool = Symbol('my-tool'); +diagnostics_channel.channel('my-channel').subscribe(onMessage, { bypassId: kMyTool }); +diagnostics_channel.bypass(kMyTool, () => { + // onMessage will NOT be called for publishes inside here +}); ``` ```cjs @@ -97,6 +104,13 @@ if (channel.hasSubscribers) { // Unsubscribe from the channel diagnostics_channel.unsubscribe('my-channel', onMessage); + +// Use bypass() to skip opted-in subscribers during internal calls +const kMyTool = Symbol('my-tool'); +diagnostics_channel.channel('my-channel').subscribe(onMessage, { bypassId: kMyTool }); +diagnostics_channel.bypass(kMyTool, () => { + // onMessage will NOT be called for publishes inside here +}); ``` #### `diagnostics_channel.hasSubscribers(name)` @@ -231,6 +245,92 @@ diagnostics_channel.subscribe('my-channel', onMessage); diagnostics_channel.unsubscribe('my-channel', onMessage); ``` +#### `diagnostics_channel.bypass(key, fn[, thisArg[, ...args]])` + + + +* `key` {symbol|Object} The bypass identity token. Must match the + `bypassId` used when subscribing. +* `fn` {Function} The function to run with bypass active. +* `thisArg` {any} The receiver to use for the function call. +* `...args` {any} Optional arguments to pass to the function. +* Returns: {any} The return value of `fn`. + +Runs `fn` with the given `key` active in the current async context. +Any channel subscribers or bound stores that were registered with +`{ bypassId: key }` will be skipped for the duration of `fn` and +any async continuations (Promises, timers, microtasks) within it. + +This is designed for observability tooling (APM agents, tracers) +that need to prevent recursive instrumentation when their own +internal code calls into an instrumented library. + +```mjs +import diagnostics_channel from 'node:diagnostics_channel'; +import { request } from 'node:http'; + +const { channel, bypass } = diagnostics_channel; + +// A unique token identifying this APM tool +const kMyTracer = Symbol('my-tracer'); + +// Subscribe to HTTP requests, but opt into bypass +channel('http.client.request').subscribe((message) => { + console.log('HTTP request:', message.url); +}, { bypassId: kMyTracer }); + +// When exporting traces internally, use bypass() so the +// above subscriber is NOT triggered for this internal request +function exportTraces(data) { + bypass(kMyTracer, () => { + // This HTTP request will NOT trigger the subscriber above + request('https://my-apm-backend.example.com/traces', { + method: 'POST', + }); + }); +} +``` + +Without `bypass()`, the internal `exportTraces()` HTTP request +would trigger the subscriber, which would try to export a trace +of the export, causing infinite recursion. + +The bypass context propagates across async boundaries: + +```mjs +// bypass() works across Promise boundaries +await bypass(kMyTracer, async () => { + await someAsyncOperation(); // still bypassed + channel('http.client.request').publish(data); // subscriber skipped +}); + +// And across timers +bypass(kMyTracer, () => { + setImmediate(() => { + // Still bypassed here + channel('http.client.request').publish(data); + }); +}); +``` + +Multiple tools can each use their own `bypassId` without +interfering with each other: + +```mjs +const kToolA = Symbol('tool-a'); +const kToolB = Symbol('tool-b'); + +channel('http.client.request').subscribe(handlerA, { bypassId: kToolA }); +channel('http.client.request').subscribe(handlerB, { bypassId: kToolB }); + +// Only handlerA is skipped, handlerB still fires +bypass(kToolA, () => { + channel('http.client.request').publish(data); +}); +``` + #### `diagnostics_channel.tracingChannel(nameOrChannels)` > Stability: 1 - Experimental @@ -972,6 +996,10 @@ dynamically. added: - v19.9.0 - v18.19.0 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/63651 + description: Added `options.bypassId` parameter. --> * `subscribers` {Object} Set of [TracingChannel Channels][] subscribers From 9f9bd81ddee068c04805c29213adbe4da5105e4c Mon Sep 17 00:00:00 2001 From: Divyanshu Sharma Date: Thu, 2 Jul 2026 02:59:15 +0530 Subject: [PATCH 4/6] doc: fix code examples in bypass documentation Signed-off-by: Divyanshu Sharma --- doc/api/diagnostics_channel.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index c4eb9ff79d2ec2..511663c4ffcbd0 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -312,9 +312,10 @@ channel('http.client.request').subscribe((message) => { function exportTraces(data) { bypass(kMyTracer, () => { // This HTTP request will NOT trigger the subscriber above - request('https://my-apm-backend.example.com/traces', { + const req = request('https://my-apm-backend.example.com/traces', { method: 'POST', }); + req.end(); }); } ``` @@ -329,32 +330,30 @@ The bypass context propagates across async boundaries: // bypass() works across Promise boundaries await bypass(kMyTracer, async () => { await someAsyncOperation(); // still bypassed - channel('http.client.request').publish(data); // subscriber skipped + channel('http.client.request').publish({}); // subscriber skipped }); // And across timers bypass(kMyTracer, () => { setImmediate(() => { // Still bypassed here - channel('http.client.request').publish(data); + channel('http.client.request').publish({}); }); }); ``` ```cjs -// bypass() works across Promise boundaries -await bypass(kMyTracer, async () => { - await someAsyncOperation(); // still bypassed - channel('http.client.request').publish(data); // subscriber skipped -}); - -// And across timers -bypass(kMyTracer, () => { - setImmediate(() => { - // Still bypassed here - channel('http.client.request').publish(data); +(async () => { + await bypass(kMyTracer, async () => { + await someAsyncOperation(); + channel('http.client.request').publish({}); }); -}); + bypass(kMyTracer, () => { + setImmediate(() => { + channel('http.client.request').publish({}); + }); + }); +})(); ``` Multiple tools can each use their own `bypassId` without @@ -369,7 +368,7 @@ channel('http.client.request').subscribe(handlerB, { bypassId: kToolB }); // Only handlerA is skipped, handlerB still fires bypass(kToolA, () => { - channel('http.client.request').publish(data); + channel('http.client.request').publish({}); }); ``` @@ -386,7 +385,7 @@ channel('http.client.request').subscribe(handlerB, { bypassId: kToolB }); // Only handlerA is skipped, handlerB still fires bypass(kToolA, () => { - channel('http.client.request').publish(data); + channel('http.client.request').publish({}); }); ``` From 556b22b09afcc756f1ac658a912d002589c53ae6 Mon Sep 17 00:00:00 2001 From: Divyanshu Sharma Date: Thu, 2 Jul 2026 03:04:25 +0530 Subject: [PATCH 5/6] doc: fix missing req.end() in MJS bypass example Signed-off-by: Divyanshu Sharma --- doc/api/diagnostics_channel.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 511663c4ffcbd0..d2cc36ecff1bdd 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -286,9 +286,10 @@ channel('http.client.request').subscribe((message) => { function exportTraces(data) { bypass(kMyTracer, () => { // This HTTP request will NOT trigger the subscriber above - request('https://my-apm-backend.example.com/traces', { + const req = request('https://my-apm-backend.example.com/traces', { method: 'POST', }); + req.end(); }); } ``` From f60e232e7ae1eacaf0a4835a4e286be298ad7790 Mon Sep 17 00:00:00 2001 From: Divyanshu Sharma Date: Thu, 2 Jul 2026 03:30:42 +0530 Subject: [PATCH 6/6] doc: fix lowercase comments in tracingChannel bypass example Signed-off-by: Divyanshu Sharma --- doc/api/diagnostics_channel.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index d2cc36ecff1bdd..741c2b42321b0a 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -1085,7 +1085,7 @@ tc.subscribe({ bypass(kMyTool, () => { tc.traceSync(() => { - // start and end handlers are NOT called + // Start and end handlers are NOT called }); }); ``` @@ -1107,7 +1107,7 @@ tc.subscribe({ bypass(kMyTool, () => { tc.traceSync(() => { - // start and end handlers are NOT called + // Start and end handlers are NOT called }); }); ```