Skip to content

feat(core, node): portable Express integration#19928

Merged
isaacs merged 2 commits intodevelopfrom
isaacschlueter/portable-express-integration
Mar 31, 2026
Merged

feat(core, node): portable Express integration#19928
isaacs merged 2 commits intodevelopfrom
isaacschlueter/portable-express-integration

Conversation

@isaacs
Copy link
Copy Markdown
Member

@isaacs isaacs commented Mar 21, 2026

This extracts the functionality from the OTel Express intstrumentation,
replacing it with a portable standalone integration in @sentry/core,
which can be extended and applied to patch any Express module import in
whatever way makes sense for the platform in question.

Currently in node, that is still an OpenTelemetry intstrumentation, but
just handling the automatic module load instrumentation, not the entire
tracing integration.

This is somewhat a proof of concept, to see what it takes to port a
fairly invovled OTel integration into a state where it can support all
of the platforms that we care about, but it does impose a bit less of a
translation layer between OTel and Sentry semantics (for example, no
need to use the no-op span.recordException()).

User-visible changes (beyond the added export in @sentry/core):

  • Express router spans have an origin of auto.http.express rather than
    auto.http.otel.express, since it's no longer technically an otel
    integration.
  • The empty measurements: {} object is no longer attached to span
    data, as that was an artifact of otel's span.recordError, which is a
    no-op anyway, and no longer executed.

Obviously this is not a full clean-room reimplementation, and relies on
the fact that the opentelemetry-js-contrib project is Apache 2.0
licensed. I included the link to the upstream license in the index file
for the Express integration, but there may be a more appropriate way to
ensure that the license is respected properly. It was arguably a
derivative work already, but simple redistribution is somewhat different
than re-implementation with subtly different context.

This reduces the node overhead and makes the Express instrumentation
portable to other SDKs, but it of course increases the bundle size of
@sentry/core considerably. It would be a good idea to explore
splitting out integrations from core, so that they're bundled and
analyzed separately, rather than shipping to all SDKs that extend core.

Closes JS-1982 (added automatically)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 21, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (core, node) Portable Express integration by isaacs in #19928

Internal Changes 🔧

  • (core) Remove provider-specific AI span attributes in favor of gen_ai attributes in sentry conventions by nicohrubec in #20011

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 21, 2026

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.

Path Size % Change Change
@sentry/browser 25.65 kB +0.02% +5 B 🔺
@sentry/browser - with treeshaking flags 24.14 kB +0.03% +5 B 🔺
@sentry/browser (incl. Tracing) 42.16 kB +0.02% +7 B 🔺
@sentry/browser (incl. Tracing, Profiling) 46.77 kB +0.02% +9 B 🔺
@sentry/browser (incl. Tracing, Replay) 80.94 kB +0.01% +5 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 70.56 kB +0.01% +5 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 85.66 kB +0.01% +8 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 97.92 kB +0.01% +5 B 🔺
@sentry/browser (incl. Feedback) 42.42 kB +0.02% +6 B 🔺
@sentry/browser (incl. sendFeedback) 30.31 kB +0.02% +6 B 🔺
@sentry/browser (incl. FeedbackAsync) 35.29 kB +0.02% +6 B 🔺
@sentry/browser (incl. Metrics) 26.96 kB +0.03% +7 B 🔺
@sentry/browser (incl. Logs) 27.11 kB +0.03% +7 B 🔺
@sentry/browser (incl. Metrics & Logs) 27.78 kB +0.03% +7 B 🔺
@sentry/react 27.41 kB +0.03% +6 B 🔺
@sentry/react (incl. Tracing) 44.48 kB +0.02% +5 B 🔺
@sentry/vue 30.08 kB +0.02% +5 B 🔺
@sentry/vue (incl. Tracing) 44.05 kB +0.02% +8 B 🔺
@sentry/svelte 25.67 kB +0.02% +5 B 🔺
CDN Bundle 28.32 kB +0.03% +6 B 🔺
CDN Bundle (incl. Tracing) 43.11 kB +0.02% +6 B 🔺
CDN Bundle (incl. Logs, Metrics) 29.68 kB +0.02% +4 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) 44.16 kB +0.02% +7 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 68.48 kB +0.01% +6 B 🔺
CDN Bundle (incl. Tracing, Replay) 80.01 kB +0.01% +7 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.05 kB +0.01% +6 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 85.55 kB +0.01% +5 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.58 kB +0.01% +6 B 🔺
CDN Bundle - uncompressed 82.68 kB +0.03% +22 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 127.83 kB +0.02% +22 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 86.83 kB +0.03% +22 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 131.24 kB +0.02% +22 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 209.81 kB +0.02% +22 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 244.7 kB +0.01% +22 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 248.1 kB +0.01% +22 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 257.62 kB +0.01% +22 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 261 kB +0.01% +22 B 🔺
@sentry/nextjs (client) 46.9 kB +0.02% +7 B 🔺
@sentry/sveltekit (client) 42.62 kB +0.02% +7 B 🔺
@sentry/node-core 55.77 kB +0.04% +17 B 🔺
@sentry/node 172.29 kB -0.27% -466 B 🔽
@sentry/node - without tracing 96.05 kB +0.05% +40 B 🔺
@sentry/aws-serverless 112.81 kB +0.03% +30 B 🔺

View base workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 21, 2026

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,097 - 9,026 +1%
GET With Sentry 1,673 18% 1,695 -1%
GET With Sentry (error only) 5,946 65% 6,154 -3%
POST Baseline 1,170 - 1,210 -3%
POST With Sentry 571 49% 595 -4%
POST With Sentry (error only) 1,014 87% 1,066 -5%
MYSQL Baseline 3,132 - 3,232 -3%
MYSQL With Sentry 369 12% 441 -16%
MYSQL With Sentry (error only) 2,533 81% 2,682 -6%

View base workflow run

@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from 3cddcee to dc1b9cf Compare March 21, 2026 23:48
@isaacs isaacs marked this pull request as draft March 21, 2026 23:48
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch 5 times, most recently from 64c45e7 to fd4fefe Compare March 22, 2026 19:04
@isaacs isaacs marked this pull request as ready for review March 22, 2026 21:03
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from 7e0d74f to db667fc Compare March 23, 2026 03:45
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from b2d4e3c to d5d4e9b Compare March 23, 2026 14:07
@linear-code linear-code bot mentioned this pull request Mar 23, 2026
24 tasks
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from f694a6b to 23f24a1 Compare March 23, 2026 18:10
@isaacs isaacs requested a review from Lms24 March 23, 2026 19:00
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from 23f24a1 to 37d4883 Compare March 24, 2026 23:53
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from ff8586c to c78e960 Compare March 26, 2026 15:50
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from c78e960 to 3c1ebe0 Compare March 26, 2026 23:38
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from 2d55c15 to 4adacd5 Compare March 27, 2026 02:54
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from fe09c38 to f87db82 Compare March 27, 2026 17:12
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from f87db82 to ad38395 Compare March 27, 2026 17:51
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from ad38395 to 15a772d Compare March 27, 2026 23:03
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from 4c52729 to f266a09 Compare March 30, 2026 14:06
Copy link
Copy Markdown
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

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

Thanks for addressing all the comments in my previous review! I had some minor suggestions but this looks good to me now!

@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from f266a09 to 6334480 Compare March 31, 2026 15:45
This extracts the functionality from the OTel Express intstrumentation,
replacing it with a portable standalone integration in `@sentry/core`,
which can be extended and applied to patch any Express module import in
whatever way makes sense for the platform in question.

Currently in node, that is still an OpenTelemetry intstrumentation, but
just handling the automatic module load instrumentation, not the entire
tracing integration.

This is somewhat a proof of concept, to see what it takes to port a
fairly invovled OTel integration into a state where it can support all
of the platforms that we care about, but it does impose a bit less of a
translation layer between OTel and Sentry semantics (for example, no
need to use the no-op `span.recordException()`).

User-visible changes (beyond the added export in `@sentry/core`):

- Express router spans have an origin of `auto.http.express` rather than
  `auto.http.otel.express`, since it's no longer technically an otel
  integration.
- The empty `measurements: {}` object is no longer attached to span
  data, as that was an artifact of otel's `span.recordError`, which is a
  no-op anyway, and no longer executed.

Obviously this is not a full clean-room reimplementation, and relies on
the fact that the opentelemetry-js-contrib project is Apache 2.0
licensed. I included the link to the upstream license in the index file
for the Express integration, but there may be a more appropriate way to
ensure that the license is respected properly. It was arguably a
derivative work already, but simple redistribution is somewhat different
than re-implementation with subtly different context.

This reduces the node overhead and makes the Express instrumentation
portable to other SDKs, but it of course *increases* the bundle size of
`@sentry/core` considerably. It would be a good idea to explore
splitting out integrations from core, so that they're bundled and
analyzed separately, rather than shipping to all SDKs that extend core.
@isaacs isaacs force-pushed the isaacschlueter/portable-express-integration branch from 6334480 to a6a6e90 Compare March 31, 2026 16:27
@linear-code
Copy link
Copy Markdown

linear-code bot commented Mar 31, 2026

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@isaacs isaacs merged commit 4b72b41 into develop Mar 31, 2026
1142 of 1166 checks passed
@isaacs isaacs deleted the isaacschlueter/portable-express-integration branch March 31, 2026 19:23
Sign up for free to 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.

2 participants