Skip to content

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

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

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

Conversation

@isaacs

@isaacsisaacs commented Mar 21, 2026

Copy link
Copy Markdown
Member

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

github-actionsBot commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

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.

Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/node/src/integrations/tracing/express.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
@github-actions

github-actionsBot commented Mar 21, 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/browser25.65 kB+0.02%+5 B 🔺
@sentry/browser - with treeshaking flags24.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 flags70.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/react27.41 kB+0.03%+6 B 🔺
@sentry/react (incl. Tracing)44.48 kB+0.02%+5 B 🔺
@sentry/vue30.08 kB+0.02%+5 B 🔺
@sentry/vue (incl. Tracing)44.05 kB+0.02%+8 B 🔺
@sentry/svelte25.67 kB+0.02%+5 B 🔺
CDN Bundle28.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 - uncompressed82.68 kB+0.03%+22 B 🔺
CDN Bundle (incl. Tracing) - uncompressed127.83 kB+0.02%+22 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed86.83 kB+0.03%+22 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed131.24 kB+0.02%+22 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed209.81 kB+0.02%+22 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed244.7 kB+0.01%+22 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed248.1 kB+0.01%+22 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed257.62 kB+0.01%+22 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed261 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-core55.77 kB+0.04%+17 B 🔺
@sentry/node172.29 kB-0.27%-466 B 🔽
@sentry/node - without tracing96.05 kB+0.05%+40 B 🔺
@sentry/aws-serverless112.81 kB+0.03%+30 B 🔺

View base workflow run

@github-actions

github-actionsBot commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

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.

ScenarioRequests/s% of BaselinePrev. Requests/sChange %
GET Baseline9,097-9,026+1%
GET With Sentry1,67318%1,695-1%
GET With Sentry (error only)5,94665%6,154-3%
POST Baseline1,170-1,210-3%
POST With Sentry57149%595-4%
POST With Sentry (error only)1,01487%1,066-5%
MYSQL Baseline3,132-3,232-3%
MYSQL With Sentry36912%441-16%
MYSQL With Sentry (error only)2,53381%2,682-6%

View base workflow run

@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from 3cddcee to dc1b9cfCompareMarch 21, 2026 23:48
@isaacs
isaacs marked this pull request as draft March 21, 2026 23:48
Comment threadpackages/node/src/integrations/tracing/express.ts Outdated
Comment threadpackages/core/src/integrations/express/index.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch 5 times, most recently from 64c45e7 to fd4fefeCompareMarch 22, 2026 19:04
@isaacs
isaacs marked this pull request as ready for review March 22, 2026 21:03
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/index.ts
Comment threadpackages/core/vite.config.ts Outdated
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from 7e0d74f to db667fcCompareMarch 23, 2026 03:45
Comment threadpackages/node-core/test/utils/ensureIsWrapped.test.ts Outdated
Comment threadpackages/core/src/integrations/express/index.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from b2d4e3c to d5d4e9bCompareMarch 23, 2026 14:07
Comment threadpackages/core/src/integrations/express/types.ts
Comment threadpackages/node/src/integrations/tracing/express.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
@linear-codelinear-codeBot mentioned this pull request Mar 23, 2026
24 tasks
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from f694a6b to 23f24a1CompareMarch 23, 2026 18:10
@isaacs
isaacs requested a review from Lms24March 23, 2026 19:00
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from 23f24a1 to 37d4883CompareMarch 24, 2026 23:53
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from ff8586c to c78e960CompareMarch 26, 2026 15:50
Comment threadpackages/core/src/integrations/express/index.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from c78e960 to 3c1ebe0CompareMarch 26, 2026 23:38
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/utils/object.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from 2d55c15 to 4adacd5CompareMarch 27, 2026 02:54
Comment threadpackages/core/src/utils/object.ts
Comment threadpackages/core/src/integrations/express/index.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from fe09c38 to f87db82CompareMarch 27, 2026 17:12
Comment threadpackages/core/src/utils/string.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from f87db82 to ad38395CompareMarch 27, 2026 17:51
Comment threadpackages/core/src/integrations/express/patch-layer.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from ad38395 to 15a772dCompareMarch 27, 2026 23:03
Comment threadpackages/core/src/integrations/express/utils.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch 2 times, most recently from 4c52729 to f266a09CompareMarch 30, 2026 14:06

@Lms24Lms24 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.

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

Comment threadpackages/core/src/integrations/express/patch-layer.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts
Comment threadpackages/core/src/integrations/express/patch-layer.ts Outdated
Comment threadpackages/core/src/integrations/express/set-sdk-processing-metadata.ts Outdated
Comment threadpackages/core/src/integrations/express/utils.ts
Comment threadpackages/core/src/integrations/express/utils.ts
@isaacs
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from f266a09 to 6334480CompareMarch 31, 2026 15:45
Comment threadpackages/core/src/integrations/express/utils.ts Outdated
Comment threadpackages/core/src/integrations/express/utils.ts
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
isaacsforce-pushed the isaacschlueter/portable-express-integration branch from 6334480 to a6a6e90CompareMarch 31, 2026 16:27
@linear-code

Copy link
Copy Markdown

Comment threadpackages/core/src/integrations/express/patch-layer.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown

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.

Comment threadpackages/core/test/lib/integrations/express/index.test.ts
@isaacs
isaacs merged commit 4b72b41 into developMar 31, 2026
1142 of 1166 checks passed
@isaacs
isaacs deleted the isaacschlueter/portable-express-integration branch March 31, 2026 19:23
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.

2 participants

@isaacs@Lms24