diagnostics_channel: add opt-in subscriber suppression via suppressedBy and suppressed()#63651
diagnostics_channel: add opt-in subscriber suppression via suppressedBy and suppressed()#63651DivyanshuX9 wants to merge 25 commits into
Conversation
Defer non-critical warnings to the next event loop iteration when can_call_into_js() returns false. This prevents crashes when V8 emits warnings during REPL preview evaluation or other contexts where JavaScript execution is temporarily forbidden. When a warning is emitted inside DisallowJavascriptExecutionScope, ProcessEmitWarningGeneric cannot be called immediately. Instead, use env->SetImmediate() to queue the warning emission for after the scope exits. This preserves full warning formatting, deprecation codes, and --redirect-warnings routing. Signed-off-by: Divyanshu Sharma <Divyanshu88999@gmail.com>
Refs: nodejs#63623 Refs: nodejs#63651 Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
5b4110a to
8b122c2
Compare
Refs: nodejs#63623 Refs: nodejs#63651 Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Refs: nodejs#63623 Refs: nodejs#63651 Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
8b122c2 to
e4aea85
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #63651 +/- ##
==========================================
+ Coverage 90.32% 90.35% +0.02%
==========================================
Files 732 732
Lines 236435 236573 +138
Branches 44527 44556 +29
==========================================
+ Hits 213563 213749 +186
+ Misses 14589 14539 -50
- Partials 8283 8285 +2
🚀 New features to boost your workflow:
|
Qard
left a comment
There was a problem hiding this comment.
Tests are missing a lot of necessary common.mustCall(fn) wrappers.
Also, it seems like this was just vibe-coded without reviewing the output before submitting the PR. Please ensure it is in a good state and that the test suite and lint passes before submitting.
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
…update tests to use common.mustCall
|
@Qard , thanks for the detailed review. So far the checklist of what i have fixed in the latest push: [] Removed the impossible ALS try/catch fallback Ready for re-review and any changes if you want, when you have time please review it. |
0f6e780 to
8fa6fd8
Compare
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
8fa6fd8 to
b8194af
Compare
|
The node_errors.cc change still seems to be present. |
…ove SetImmediate deferral) Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
|
Is this naming you want @BridgeAR ?
have a quick look so i would start changes |
|
Also for the documentation i think we should open new issue/pr , is this fine @BridgeAR ? |
|
@DivyanshuX9 yes, I like that naming more, while I think it would be agreed upon by @nodejs/diagnostics as a whole. What about a short survey: ❤️ bypass In addition: we did not yet agree on the API. @bengl asked for #63623 (comment) I do not think this would work as suggested, while the current callback API would (it is meant as drop in replacement for |
|
@BridgeAR , i'll just voted ❤️ for bypass, agrees with your reasoning. On the API shape , I implemented the callback style Happy to wait for @bengl and @nodejs/diagnostics to weigh in before making further changes to the API shape. Should I hold off on the rename until the vote settles, or go ahead with bypass now since that seems to be the leading preference? Happy to rename again whenever the vote settles although I've gotten good at find-and-replace at this point 😄 (Note: currently still named suppressed/subscriberId in the code will rename to whatever the team settles on from the vote) |
9621180 to
fcb55c2
Compare
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
fcb55c2 to
3fdcd8e
Compare
|
@BridgeAR ,I fixed two issues in the latest push:
CI is running. Once the naming vote settles I'll do the full rename in a single commit. |
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
|
How is this meant to be used? I've been following the issue and this PR but I still don't understand how this would be used in the real world 😅 Can proper examples be added somewhere? |
|
@rochdev ok that's a good question, feature is not for application developers, it's for observability vendors (Datadog, OpenTelemetry, New Relic, Elastic APM, Sentry, etc.). I can add a similar example to the PR description(hopefully if i get permission to edit docs ) if this clarifies the use case. |
That would help a lot! I understand the underlying need (I work at an APM vendor after all) but I don't understand how this solves the issue in the correct way. It seems to me that it introduces coupling between the publisher and subscriber and goes in the opposite direction we're trying to go (upstreaming instrumentation in the libraries themselves so everyone can benefit without every vendor having their own instrumentation). I may be wrong though as without an example I'm not 100% sure how this is meant to be used, especially when the publisher and subscribers are in separate projects. |
bengl
left a comment
There was a problem hiding this comment.
This needs to handle TracingChannel casses where suppression is triggered on the subscriber side, like I mentioned in the original issue.
Also, let's get rid of the word "suppression" and replace it with "bypass" everywhere.
|
@rochdev great point, let me clarify with a concrete example. The publisher does not need to know anything about suppression. // Datadog's HTTP tracer subscribes and says "skip me when I'm
// doing my own internal work"
const kDatadog = Symbol('datadog');
channel('http.request').subscribe(handler, { subscriberId: kDatadog });
// When Datadog exports traces (internal HTTP request), it wraps
// that call in suppressed() so its own handler is skipped
suppressed(kDatadog, () => {
exportTracesToBackend(); // makes HTTP request internally
});
// handler is NOT called for this internal request
// handler IS called for all application HTTP requestsThe publisher ( Happy to add this example to the PR description, if it feels more helpful. |
|
@bengl ,ok thanks for the review. A few questions before I make changes:
On the rename to bypass -> doing that now. |
…stics_channel Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
…cs_channel Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
Summary
Adds opt-in subscriber suppression to
diagnostics_channelso APMagents can prevent recursive instrumentation when their own internal
code calls into instrumented libraries.
What Changed
lib/diagnostics_channel.jssuppressed(key, fn, thisArg, ...args)- runsfnwiththe given key active in the current async context
subscribe()andbindStore()accept{ subscriberId }optionpath has zero overhead, ALS is only hit when bypass subscribers exist
AsyncLocalStorageinitialization viagetSuppressionsStorage()async_hooks is available
validateBypassKey()helper for all key validationtest/parallel/test-diagnostics-channel-suppression.jsstore, nested, and type validation cases
Why
APM agents currently implement suppression themselves using a
custom ALS noop marker - every vendor reimplements the same
pattern differently. Moving it into core:
Backward Compatibility
Naming
Currently using
suppressed/subscriberId- pending team voteon final naming (
bypass,suppress,silence, orignore).Will rename in a single commit once consensus is reached.