Skip to content

Sentry

autotel-sentry sends Autotel traces to Sentry over OTLP. It parses a Sentry DSN into the OTLP endpoint and auth headers that Autotel’s init() expects.

That is the whole package. Errors line up with traces on their own: @sentry/node reads the active OpenTelemetry span when it builds an event, so a captured error already carries the right trace_id and span_id.

[!NOTE] Earlier versions used a SentrySpanProcessor / SentryPropagator bridge built on deprecated Sentry Hub APIs. That bridge is removed. Sentry SDK v8+ ships its own OTel SDK, so Autotel owns OTel and exports straight to Sentry’s OTLP endpoint. No custom span processor.

  • Node.js 22+
  • autotel
  • @sentry/node, to capture the errors. autotel-sentry calls no Sentry API and declares no dependency on it.
Terminal window
npm install autotel autotel-sentry @sentry/node
import * as Sentry from '@sentry/node';
import { init } from 'autotel';
import { sentryOtlpConfig } from 'autotel-sentry';
const config = sentryOtlpConfig(process.env.SENTRY_DSN!);
// 1. Initialize Sentry. Tell it not to register its own OTel SDK.
Sentry.init({ dsn: config.dsn, skipOpenTelemetrySetup: true });
// 2. Initialize Autotel. It owns OTel and exports traces to Sentry's OTLP endpoint.
init({ service: 'my-app', endpoint: config.endpoint, headers: config.headers });

skipOpenTelemetrySetup: true is required. Sentry SDK v8+ registers its own OTel SDK internally, and Autotel owns OTel setup. Without the flag you get duplicate span processors and broken traces.

sentryOtlpConfig(dsn: string): SentryOtlpConfig

Section titled “sentryOtlpConfig(dsn: string): SentryOtlpConfig”

Parses a Sentry DSN and returns the three values that wire Autotel to Sentry’s OTLP ingestion endpoint. Throws when the DSN is missing or cannot be parsed.

const config = sentryOtlpConfig(
'https://<key>@o<org>.ingest.sentry.io/<project>',
);
// config.dsn normalized DSN string (pass to Sentry.init)
// config.endpoint OTLP base URL (pass to Autotel init as `endpoint`)
// config.headers auth headers (pass to Autotel init as `headers`)

A Sentry SDK in the browser or a mobile app generates its own trace ids and does not send W3C traceparent by default, so your frontend and your Autotel backend end up in two unconnected traces. Turn on propagateTraceparent, and enable browser tracing so something actually instruments the requests:

Sentry.init({
dsn: 'YOUR_DSN',
// Plain @sentry/browser does not auto-enable this. Without it nothing
// instruments fetch/XHR and no header is attached, whatever
// propagateTraceparent says. Framework SDKs enable it for you.
integrations: [Sentry.browserTracingIntegration()],
tracesSampleRate: 1.0,
propagateTraceparent: true,
});

The header carries the frontend’s sampling decision, and a parentbased_* sampler honours it. parentbased_always_on is the OpenTelemetry default, so your backend stops deciding for itself and a tail-based sampler in your collector never sees the spans it is meant to judge. Set OTEL_TRACES_SAMPLER=always_on on the backend to take that decision back.

If autotel-web is also on the page, only one of them can own the header. Both inject traceparent only when it is absent, so whichever is initialized last wraps the other and wins for fetch. XHR does not follow that rule, because both SDKs inject during send() rather than by wrapping. So when Sentry is meant to own propagation, set both instrumentFetch: false and instrumentXHR: false on autotel-web rather than relying on initialization order; otherwise fetch and XHR can land in different traces.

Removed in 0.7.0. Delete the call and its import; nothing replaces it. @sentry/node reads the active OpenTelemetry span when it builds an event, so errors keep landing on the right trace without it. The SentryLinkable type is gone too.

  • example-sentry: traces and logs over OTLP, with captured errors on the active trace.