feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion - #21981

Merged
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion
Jul 9, 2026
Merged

feat(server-utils): Migrate @opentelemetry/instrumentation-amqplib to orchestrion#21981
s1gr1d merged 13 commits into
developfrom
sig/amqplib-orchestrion

Conversation

@s1gr1d

Copy link
Copy Markdown
Member

Adds amqplibChannelIntegration in @sentry/server-utils for injecting orchestrion channels into amqplib.

  • A bindTracingChannelToSpan-based subscriber builds publisher/consumer spans; span-building helpers are ported with attributes from @sentry/conventions/attributes, preserving span semantics (long-lived consumer spans, header trace propagation, confirm-channel guard).
  • Wired for Node (via experimentalUseDiagnosticsChannelInjection()), Bun (automatic), and Deno (denoAmqplibIntegration wrapper).

Closes#20747

Linear: https://linear.app/getsentry/issue/JS-2398/rewrite-opentelemetryinstrumentation-amqplib-to-orchestrion

@s1gr1d
s1gr1d requested a review from a team as a code ownerJuly 6, 2026 12:04
@s1gr1d
s1gr1d requested review from a team, JPeer264, andreiborza, isaacs, mydea and nicohrubec and removed request for a teamJuly 6, 2026 12:04

@JPeer264JPeer264 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

const ATTR_MESSAGING_CONVERSATION_ID = 'messaging.conversation_id';
const MESSAGING_DESTINATION_KIND_VALUE_TOPIC = 'topic';
const MESSAGING_OPERATION_VALUE_PROCESS = 'process';
// Inlined (rather than imported) because the `@sentry/conventions` exports are deprecated; the SDK

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think it is ok to import from @sentry/conventions/attributes here and oxlint-disable this, this is what has been done in other integrations as well AFAIK

const PUBLISHER_ORIGIN = 'auto.amqplib.orchestrion.publisher';
const CONSUMER_ORIGIN = 'auto.amqplib.orchestrion.consumer';

// Legacy messaging semantic-conventions, inlined to keep this integration free of `@opentelemetry/*`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we add a v11 todo to check on these attributes? Not sure if there is already a general initiative to change these in v11

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed all of this again to use the already existing attributes alongside the ones we already use in semantic conventions. Also added two missing attributes: getsentry/sentry-conventions#469

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: Do you think it makes sense to reuse certain functions like this one in the vendored OTel library?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is definitely something we should do in a follow-up

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deno test failure is straightforward, just need to add the lib to the default set in the snapshots, looks like.

Once that's resolved, LGTM!

// The span origin depends on which instrumentation is active. These blocks drive the SDK's default
// integrations, so when the generic orchestrion run is enabled (via INJECT_ORCHESTRION) the OTel
// `Amqplib` integration is swapped for the diagnostics-channel one, changing the origin.
const PUBLISHER_ORIGIN = isOrchestrionEnabled() ? 'auto.amqplib.orchestrion.publisher' : 'auto.amqplib.otel.publisher';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +368 to +378
channel.on('close', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelClosed, undefined);
const activeTimer = channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if (activeTimer) {
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER] = undefined;
});
channel.on('error', () => {
endAllSpansOnChannel(channel, true, END_OP.ChannelError, undefined);
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get an error without a close, could this leave the active timer dangling? If not, ignore this, but it could be good to clear it in either the error or close cases?

Suggested change
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
}
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
});
// could also move this out of this closure, take the channel as an arg, etc.
functionclearActiveTimer(){
constactiveTimer=channel[CHANNEL_CONSUME_TIMEOUT_TIMER];
if(activeTimer){
clearInterval(activeTimer);
channel[CHANNEL_CONSUME_TIMEOUT_TIMER]=undefined;
}
}
channel.on('close',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelClosed,undefined);
clearActiveTimer();
});
channel.on('error',()=>{
endAllSpansOnChannel(channel,true,END_OP.ChannelError,undefined);
clearActiveTimer();
});

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, close should be emitted after error (https://amqp-node.github.io/amqplib/channel_api.html#model_events). But this is still a good hardening of the code 👍

}
}

function checkConsumeTimeoutOnChannel(channel: ChannelLike): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's going to be a bunch of these (similar note came up on the nestjs instrumentation). I think the thing to do is sort of just accept that there's a bit of duplication, and then do a sweeping DRY-up refactor.

The reason is we may decide on a few different possible directions once we see it all, so it's kind of high risk of wasted effort to pick one now. Eg:

  • delete the OTelJS iitm/ritm based integrations entirely (ie, de-experimental-ize the nodejs orchestrion).
  • organize the server-utils/src/integrations/tracing-channel into some set of isolated or bundled library
  • improve tree-shaking so only the ones in use get pulled in
  • maybe do some kind of dependency-injection at build/preload time for the config and channel definitions.

It's hard to say at this point what's going to be worth the effort, what'll be overkill, etc., so maybe best to just procrastinate the cleanup a little bit.

s1gr1d added 5 commits July 8, 2026 10:18
# Conflicts:
#	packages/server-utils/src/orchestrion/channels.ts
#	packages/server-utils/src/orchestrion/config/index.ts
#	packages/server-utils/src/orchestrion/index.ts
@github-actions

github-actionsBot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

PathSize% ChangeChange
@sentry/browser27.59 kB--
@sentry/browser - with treeshaking flags26.03 kB--
@sentry/browser (incl. Tracing)46.34 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.13 kB--
@sentry/browser (incl. Tracing, Profiling)51.12 kB--
@sentry/browser (incl. Tracing, Replay)85.62 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.26 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.32 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.97 kB--
@sentry/browser (incl. Feedback)44.76 kB--
@sentry/browser (incl. sendFeedback)32.38 kB--
@sentry/browser (incl. FeedbackAsync)37.51 kB--
@sentry/browser (incl. Metrics)28.67 kB--
@sentry/browser (incl. Logs)28.91 kB--
@sentry/browser (incl. Metrics & Logs)29.59 kB--
@sentry/react29.38 kB--
@sentry/react (incl. Tracing)48.61 kB--
@sentry/vue33.03 kB--
@sentry/vue (incl. Tracing)48.24 kB--
@sentry/svelte27.61 kB--
CDN Bundle30 kB--
CDN Bundle (incl. Tracing)48.32 kB--
CDN Bundle (incl. Logs, Metrics)31.57 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.64 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.81 kB--
CDN Bundle (incl. Tracing, Replay)85.84 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.64 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.92 kB--
CDN Bundle - uncompressed89.35 kB--
CDN Bundle (incl. Tracing) - uncompressed146.1 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.05 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.07 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.78 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.3 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.26 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.95 kB--
@sentry/nextjs (client)51.16 kB--
@sentry/sveltekit (client)46.78 kB--
@sentry/core/server78.42 kB--
@sentry/core/browser64.74 kB--
@sentry/node-core62.72 kB--
@sentry/node125.37 kB-0.01%-1 B 🔽
@sentry/node (incl. diagnostics channel injection)138.54 kB+1.57%+2.13 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.72 kB-0.01%-1 B 🔽
@sentry/node - without tracing74.06 kB+0.01%+1 B 🔺
@sentry/aws-serverless85.5 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified181.71 kB--
@sentry/cloudflare (withSentry)449.16 kB--

View base workflow run

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove the unit tests? They set up an ACS that has no place in unit tests. If functionality like that has to be tested then it should be done in an integration tests.

Most of the stuff in the unit tests should already be covered anyway, but I suggest to pick the differences and move them up.

See #22103 for example.

s1gr1d added 2 commits July 9, 2026 10:17
# Conflicts:
#	.size-limit.js
#	packages/server-utils/src/orchestrion/config/index.ts
@s1gr1d
s1gr1dforce-pushed the sig/amqplib-orchestrion branch from 3afe4b8 to 5e93d20CompareJuly 9, 2026 08:34

@andreiborzaandreiborza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unit test removal 👍

@s1gr1d
s1gr1d enabled auto-merge (squash) July 9, 2026 11:24
@s1gr1d
s1gr1d merged commit 17a21ff into developJul 9, 2026
595 of 597 checks passed
@s1gr1d
s1gr1d deleted the sig/amqplib-orchestrion branch July 9, 2026 12:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite @opentelemetry/instrumentation-amqplib to orchestrion

4 participants

@s1gr1d@isaacs@JPeer264@andreiborza