Skip to content

feat(node-core): Add OTLP integration for node-core/light#19729

Open
andreiborza wants to merge 5 commits intodevelopfrom
ab/otlp-integration
Open

feat(node-core): Add OTLP integration for node-core/light#19729
andreiborza wants to merge 5 commits intodevelopfrom
ab/otlp-integration

Conversation

@andreiborza
Copy link
Member

@andreiborza andreiborza commented Mar 10, 2026

Added otlpIntegration at @sentry/node-core/light/otlp for users who manage their own OpenTelemetry setup and want to send trace data to Sentry without adopting the full @sentry/node SDK.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import * as Sentry from '@sentry/node-core/light';
import { otlpIntegration } from '@sentry/node-core/light/otlp';

const provider = new NodeTracerProvider();
provider.register();

Sentry.init({
  dsn: '__DSN__',
  integrations: [
    otlpIntegration({
      // Export OTel spans to Sentry via OTLP (default: true)
      setupOtlpTracesExporter: true,
      // Send traces to a custom collector instead of the DSN-derived endpoint (default: undefined)
      collectorUrl: 'https://my-collector.example.com/v1/traces',
    }),
  ],
});

The integration links Sentry errors to OTel traces and exports spans to Sentry via OTLP.


Split up for easier reviewing:

External propagation context support: 64cf942c5
OTLP integration: 4431f598c
E2E test app: 33f4e09de
CHANGELOG entry: 7cc6de292

@andreiborza andreiborza changed the title Ab/otlp integration feat(node-core): Add OTLP integration for node-core/light Mar 10, 2026
Copy link

@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 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Stray backtick fences break entire CHANGELOG rendering
    • Removed the stray 4-backtick sequences at lines 64 and 3802 that were creating an unintended code block wrapping the entire CHANGELOG content.
  • ✅ Fixed: getTraceData checks registration instead of actual context value
    • Changed from hasExternalPropagationContext() to getExternalPropagationContext() to check for actual context value, ensuring proper fallback to Sentry's scope-based propagation when no OTel span is active.

Create PR

Or push these changes by commenting:

@cursor push c64695209a
Preview (c64695209a)
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,8 +61,6 @@
   });

-````

Other Changes

  • "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
    @@ -3799,4 +3797,3 @@

4.x

A full list of changes in the 4.x release of the SDK can be found in the 4.x Changelog.
-````

diff --git a/packages/core/src/utils/traceData.ts b/packages/core/src/utils/traceData.ts
--- a/packages/core/src/utils/traceData.ts
+++ b/packages/core/src/utils/traceData.ts
@@ -1,7 +1,7 @@
import { getAsyncContextStrategy } from '../asyncContext';
import { getMainCarrier } from '../carrier';
import type { Client } from '../client';
-import { getClient, getCurrentScope, hasExternalPropagationContext } from '../currentScopes';
+import { getClient, getCurrentScope, getExternalPropagationContext } from '../currentScopes';
import { isEnabled } from '../exports';
import type { Scope } from '../scope';
import { getDynamicSamplingContextFromScope, getDynamicSamplingContextFromSpan } from '../tracing';
@@ -49,7 +49,7 @@

// When no active span and external propagation context is registered (e.g. OTLP integration),
// return empty to let the OTel propagator handle outgoing request propagation.

  • if (!span && hasExternalPropagationContext()) {
  • if (!span && getExternalPropagationContext()) {
    return {};
    }

</details>
<sub>This Bugbot Autofix run was free. To enable autofix for future PRs, go to the <a href="https://www.cursor.com/dashboard?tab=bugbot">Cursor dashboard</a>.</sub>

</details>

@andreiborza andreiborza force-pushed the ab/otlp-integration branch 2 times, most recently from 5f20150 to e1f9019 Compare March 10, 2026 09:54
@andreiborza andreiborza force-pushed the ab/otlp-integration branch from e1f9019 to 9e9c617 Compare March 10, 2026 10:05
@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 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.64 kB +0.02% +5 B 🔺
@sentry/browser - with treeshaking flags 24.14 kB +0.03% +6 B 🔺
@sentry/browser (incl. Tracing) 42.63 kB +0.03% +9 B 🔺
@sentry/browser (incl. Tracing, Profiling) 47.29 kB +0.03% +10 B 🔺
@sentry/browser (incl. Tracing, Replay) 81.43 kB +0.01% +8 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71 kB +0.01% +7 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 86.13 kB +0.01% +7 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 98.39 kB +0.02% +12 B 🔺
@sentry/browser (incl. Feedback) 42.45 kB +0.02% +7 B 🔺
@sentry/browser (incl. sendFeedback) 30.32 kB +0.02% +6 B 🔺
@sentry/browser (incl. FeedbackAsync) 35.37 kB +0.02% +7 B 🔺
@sentry/browser (incl. Metrics) 26.95 kB +0.12% +30 B 🔺
@sentry/browser (incl. Logs) 27.09 kB +0.1% +25 B 🔺
@sentry/browser (incl. Metrics & Logs) 27.77 kB +0.11% +30 B 🔺
@sentry/react 27.4 kB +0.05% +12 B 🔺
@sentry/react (incl. Tracing) 44.96 kB +0.03% +12 B 🔺
@sentry/vue 30.09 kB +0.01% +3 B 🔺
@sentry/vue (incl. Tracing) 44.49 kB +0.03% +9 B 🔺
@sentry/svelte 25.67 kB +0.02% +4 B 🔺
CDN Bundle 28.27 kB - -
CDN Bundle (incl. Tracing) 43.5 kB - -
CDN Bundle (incl. Logs, Metrics) 29.13 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.34 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.2 kB - -
CDN Bundle (incl. Tracing, Replay) 80.32 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.22 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 85.86 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.76 kB - -
CDN Bundle - uncompressed 82.56 kB - -
CDN Bundle (incl. Tracing) - uncompressed 128.5 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 85.43 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 131.37 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 209.06 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 245.35 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 248.21 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 258.26 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 261.11 kB - -
@sentry/nextjs (client) 47.38 kB +0.03% +10 B 🔺
@sentry/sveltekit (client) 43.08 kB +0.02% +6 B 🔺
@sentry/node-core 56.34 kB +0.04% +17 B 🔺
@sentry/node 173.2 kB +0.01% +15 B 🔺
@sentry/node - without tracing 96.36 kB +0.02% +10 B 🔺
@sentry/aws-serverless 113.35 kB +0.02% +16 B 🔺

View base workflow run

Comment on lines +52 to +53
if (!span && hasExternalPropagationContext()) {
return {};
Copy link
Member

Choose a reason for hiding this comment

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

q: Could this be silently breaking for some users with a custom setup?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can't really think of a use-case where it might. Typically if hasExternalPropagationContext evaluates true, the user has set up tracing via OTel, so there should be a spann

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 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 8,759 - 9,238 -5%
GET With Sentry 1,678 19% 1,653 +2%
GET With Sentry (error only) 6,043 69% 6,102 -1%
POST Baseline 1,188 - 1,160 +2%
POST With Sentry 572 48% 583 -2%
POST With Sentry (error only) 1,024 86% 1,033 -1%
MYSQL Baseline 3,215 - 3,288 -2%
MYSQL With Sentry 441 14% 446 -1%
MYSQL With Sentry (error only) 2,589 81% 2,610 -1%

View base workflow run

@andreiborza andreiborza force-pushed the ab/otlp-integration branch from 304c86a to 8192218 Compare March 10, 2026 10:35
client.on('close', () => {
void _spanProcessor?.shutdown();
void _tracerProvider?.shutdown();
});
Copy link

Choose a reason for hiding this comment

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

Span flush not awaited on client flush/close

Medium Severity

The flush and close event handlers use void to discard the promises from _spanProcessor?.forceFlush() and _spanProcessor?.shutdown(). Since client.emit('flush') is synchronous and doesn't await handler return values, Sentry.flush() and Sentry.close() resolve before the OTel span processor finishes exporting spans. This can cause data loss in serverless or CLI-exit scenarios where the process ends right after flushing.

Fix in Cursor Fix in Web

@andreiborza andreiborza force-pushed the ab/otlp-integration branch from 8192218 to 6c76bcd Compare March 10, 2026 11:01
@andreiborza andreiborza force-pushed the ab/otlp-integration branch from 6c76bcd to 9f09a31 Compare March 10, 2026 13:15
@andreiborza andreiborza force-pushed the ab/otlp-integration branch from 9f09a31 to c2dc1b5 Compare March 10, 2026 14:49
Copy link
Member

@JPeer264 JPeer264 left a comment

Choose a reason for hiding this comment

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

LGTM

@andreiborza andreiborza force-pushed the ab/otlp-integration branch from c2dc1b5 to 52436f7 Compare March 11, 2026 10:16
@andreiborza andreiborza force-pushed the ab/otlp-integration branch 2 times, most recently from 2b22df3 to d191df4 Compare March 11, 2026 21:09
@andreiborza andreiborza force-pushed the ab/otlp-integration branch 2 times, most recently from 9acb433 to 378e7ed Compare March 12, 2026 11:01
@andreiborza andreiborza force-pushed the ab/otlp-integration branch 3 times, most recently from 8c37f9c to 5dfa140 Compare March 13, 2026 15:56
andreiborza and others added 5 commits March 13, 2026 16:57
Added `otlpIntegration` at `@sentry/node-core/light/otlp` for users who manage their own OpenTelemetry setup
and want to send trace data to Sentry without adopting the full `@sentry/node` SDK.

```js
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import * as Sentry from '@sentry/node-core/light';
import { otlpIntegration } from '@sentry/node-core/light/otlp';

const provider = new NodeTracerProvider();
provider.register();

Sentry.init({
  dsn: '__DSN__',
  integrations: [
    otlpIntegration({
      // Export OTel spans to Sentry via OTLP (default: true)
      setupOtlpTracesExporter: true,
      // Send traces to a custom collector instead of the DSN-derived endpoint (default: undefined)
      collectorUrl: 'https://my-collector.example.com/v1/traces',
    }),
  ],
});
```

The integration links Sentry errors to OTel traces and exports spans to Sentry via OTLP.

Co-Authored-By: Claude claude-opus-4-6 <noreply@anthropic.com>
@andreiborza andreiborza force-pushed the ab/otlp-integration branch from 5dfa140 to 7cc6de2 Compare March 13, 2026 16:03
Copy link

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

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants