ref(cloudflare)!: Use shared SentryTracerProvider for OpenTelemetry interop - #23300
Conversation
size-limit report 📦
|
ed6e9c1 to
359e1f3
Compare
| export function wrapRequestHandler( | ||
| wrapperOptions: RequestHandlerWrapperOptions, | ||
| wrapperOptions: Omit<RequestHandlerWrapperOptions, 'options'> & { | ||
| // `enableOpenTelemetrySetup` is only honored by `init` from `sdk.ts`; this entry point | ||
| // initializes the SDK via `initBaseSdk`, where setting it would have no effect. | ||
| options: Omit<CloudflareOptions, 'enableOpenTelemetrySetup'>; | ||
| }, | ||
| handler: (...args: unknown[]) => Response | Promise<Response>, | ||
| ): Promise<Response> { | ||
| return wrapRequestHandlerWithInit(wrapperOptions, handler, initBaseSdk); |
There was a problem hiding this comment.
Bug: The wrapRequestHandler no longer accepts enableOpenTelemetrySetup, but the SvelteKit integration still passes it. This will silently disable SvelteKit's OpenTelemetry tracing on Cloudflare.
Severity: MEDIUM
Suggested Fix
Update the SvelteKit integration to handle this change. Either switch to using the main init function from sdk.ts which still honors enableOpenTelemetrySetup, or remove the enableOpenTelemetrySetup: true setting from the options passed to wrapRequestHandler.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: packages/cloudflare/src/request.ts#L54-L62
Potential issue: The `wrapRequestHandler` function's options type was changed to
`Omit<CloudflareOptions, 'enableOpenTelemetrySetup'>`, explicitly removing support for
this option from the `/request` entrypoint. However, the SvelteKit integration was not
updated and continues to pass `enableOpenTelemetrySetup: true` to this function. While
this is a TypeScript type error, at runtime the property is silently ignored. This
causes a functional regression where SvelteKit's own OpenTelemetry spans (for Kit
tracing) will no longer be captured by Sentry when deployed on Cloudflare, as the
necessary tracer setup is skipped.
Also affects:
packages/cloudflare/src/baseSdk.ts:18~23
Did we get this right? 👍 / 👎 to inform future reviews.
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 359e1f3. Configure here.
… interop Replaces the bespoke Cloudflare tracer with `SentryTracerProvider` from `@sentry/opentelemetry`, and covers `enableOpenTelemetrySetup` end to end in workerd with two integration suites. The enabled suite documents that `startActiveSpan` detaches into a root transaction of its own rather than nesting under the request span: it always resolves an explicit context, and Cloudflare installs no OTel context manager, so `context.active()` never carries the request span. `startSpan` passes no context and does nest, so both paths are asserted to pin the difference. The two workers are kept identical apart from the option itself, so the disabled suite also proves the wider OTel surface stays inert when the provider is off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ager Without a context manager (e.g. Cloudflare) `context.with` runs the callback directly, so the span set on the current scope leaked past the callback and later spans parented to it. Fork the scope in that case, and detect the parent of an ignored span through `getActiveSpan()` so it is not made active either.
359c804 to
1377b41
Compare
| if (spanIsIgnored(span) && this._hasParentSpan(options, explicitCtx)) { | ||
| return context.with(withCapturedIsolationScope(ctx), () => callback(span)) as ReturnType<F>; |
There was a problem hiding this comment.
Bug: On runtimes without an OTel context manager (e.g., Cloudflare), the callback for an ignored span can mutate and pollute the parent scope because it doesn't fork the scope.
Severity: MEDIUM
Suggested Fix
Wrap the callback for the ignored span path in a withScope call, similar to how the non-ignored span path is handled. This will ensure a new scope is forked, isolating any scope mutations within the callback and preventing them from polluting the parent scope.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: packages/opentelemetry/src/tracer.ts#L95-L96
Potential issue: On runtimes without an OTel context manager, such as Cloudflare, the
code path for an ignored span within `startActiveSpan` does not fork the Sentry scope.
The `context.with` call runs the callback synchronously without creating a new scope. If
the callback mutates the scope (e.g., by calling `scope.addBreadcrumb()` or
`scope.setTag()`), these changes will leak and persist on the parent scope after the
callback completes. This is inconsistent with the non-ignored span path, which
explicitly uses `withScope` to prevent such pollution.
… interop (#23300) This uses now the `SentryTracerProvider` and removes the previous kinda mocked provider. I added two integration tests that check if OTel traces are picked up by our provider—just to tripple check if the machinery is implemented correctly. I made it breaking since the `sentry.cloudflare_tracer` attribute is being removed now (I added this as a fixup in the migration guide) Also for Hydrogen aka the `/request` entrypoint, we no longer support the `enableOpenTelemetrySetup` option, as this would require `node:async_hooks`, which isn't available in Hydrogen. In case this would be needed in the future we can enable this and readd the previous OTel Tracer Provider. But for now it is better to keep it simple. ### Keep an eye on this 👀 I had to adjust `startActiveSpan` in order to not mess with the root span: https://github.com/getsentry/sentry-javascript/actions/runs/31579946168/job/94061924393 --- Clanker machinery comment: Replaces the bespoke Cloudflare tracer with `SentryTracerProvider` from `@sentry/opentelemetry`, and covers `enableOpenTelemetrySetup` end to end in workerd with two integration suites. The enabled suite documents that `startActiveSpan` detaches into a root transaction of its own rather than nesting under the request span: it always resolves an explicit context, and Cloudflare installs no OTel context manager, so `context.active()` never carries the request span. `startSpan` passes no context and does nest, so both paths are asserted to pin the difference. The two workers are kept identical apart from the option itself, so the disabled suite also proves the wider OTel surface stays inert when the provider is off. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

This uses now the
SentryTracerProviderand removes the previous kinda mocked provider. I added two integration tests that check if OTel traces are picked up by our provider—just to tripple check if the machinery is implemented correctly.I made it breaking since the
sentry.cloudflare_tracerattribute is being removed now (I added this as a fixup in the migration guide)Also for Hydrogen aka the
/requestentrypoint, we no longer support theenableOpenTelemetrySetupoption, as this would requirenode:async_hooks, which isn't available in Hydrogen. In case this would be needed in the future we can enable this and readd the previous OTel Tracer Provider. But for now it is better to keep it simple.Keep an eye on this 👀
I had to adjust
startActiveSpanin order to not mess with the root span: https://github.com/getsentry/sentry-javascript/actions/runs/31579946168/job/94061924393Clanker machinery comment:
Replaces the bespoke Cloudflare tracer with
SentryTracerProviderfrom@sentry/opentelemetry, and coversenableOpenTelemetrySetupend to end in workerd with two integration suites.The enabled suite documents that
startActiveSpandetaches into a root transaction of its own rather than nesting under the request span: it always resolves an explicit context, and Cloudflare installs no OTel context manager, socontext.active()never carries the request span.startSpanpasses no context and does nest, so both paths are asserted to pin the difference.The two workers are kept identical apart from the option itself, so the disabled suite also proves the wider OTel surface stays inert when the provider is off.