Skip to content

feat(cloudflare): Add Spotlight integration for local dev event forwarding#22490

Open
MathurAditya724 wants to merge 6 commits into
developfrom
feat/cloudflare-spotlight-integration
Open

feat(cloudflare): Add Spotlight integration for local dev event forwarding#22490
MathurAditya724 wants to merge 6 commits into
developfrom
feat/cloudflare-spotlight-integration

Conversation

@MathurAditya724

@MathurAditya724 MathurAditya724 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

Add a fetch-based spotlightIntegration to @sentry/cloudflare that mirrors Sentry envelopes to a local Spotlight sidecar during development. Cloudflare Workers was the only server SDK without Spotlight support.

What this enables

  • spotlight: true in Sentry.init() (or withSentry) forwards all envelopes (errors, transactions, logs, AI spans) to http://localhost:8969/stream
  • SENTRY_SPOTLIGHT wrangler env binding (boolean or custom URL) for zero-code-change enablement
  • Works with sentry local serve from the Sentry CLI for a complete local dev experience

Changes

  • New integration src/integrations/spotlight.ts — uses fetch with suppressTracing (CF instruments outbound fetch), consumes response body (Workers requirement), disables after >3 failures
  • sdk.ts — wire integration in init() behind a runtime if (options.spotlight) guard (matches the node-core pattern)
  • options.ts — read SENTRY_SPOTLIGHT from CF env binding with the same precedence as node-core's getSpotlightConfig (user option > env boolean > env URL)
  • client.ts — add spotlight?: boolean | string to BaseCloudflareOptions (CloudflareOptions extends Options/CoreOptions, which does not include ServerRuntimeOptions where spotlight normally lives)
  • index.ts — export spotlightIntegration
  • Tests — full coverage for integration (10 tests) + options (9 new tests), all existing tests still pass

Why fetch, not node:http

Cloudflare Workers don't have node:http. The integration mirrors the browser SDK's fetch-based approach but adds suppressTracing (like Node) since CF's fetchIntegration instruments all outbound fetch, and drains the response body (Workers-specific requirement, same as the CF transport).

Production behavior

Spotlight forwarding only activates when options.spotlight is truthy, which is falsy in production by default — identical to how @sentry/node, @sentry/bun, and all other server SDKs ship the spotlight integration. Each forwarded envelope counts as a Worker subrequest (cap 50 free / 1000 paid), documented in the integration JSDoc; keep it disabled in production.

…rding

Add a fetch-based spotlightIntegration to @sentry/cloudflare that mirrors
envelopes to a local Spotlight sidecar during development. This closes the
gap where Cloudflare Workers was the only server SDK without Spotlight support.

- New integration at src/integrations/spotlight.ts using fetch + suppressTracing
- Wire in sdk.ts init() with rollup-include-development-only markers (stripped from prod builds)
- Read SENTRY_SPOTLIGHT from CF env binding in getFinalOptions (boolean or URL)
- Export spotlightIntegration from package index
- Full test coverage (integration tests + options tests)
CloudflareOptions extends Options (CoreOptions) which does not include
ServerRuntimeOptions where spotlight is declared. Add the property
directly to BaseCloudflareOptions so TypeScript resolves it correctly.
@github-actions

github-actions Bot commented Jul 22, 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.

Path Size % Change Change
@sentry/browser 27.78 kB - -
@sentry/browser - with treeshaking flags 26.22 kB - -
@sentry/browser (incl. Tracing) 46.61 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.42 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.41 kB - -
@sentry/browser (incl. Tracing, Replay) 85.85 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 75.5 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 90.58 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 103.24 kB - -
@sentry/browser (incl. Feedback) 44.97 kB - -
@sentry/browser (incl. sendFeedback) 32.58 kB - -
@sentry/browser (incl. FeedbackAsync) 37.64 kB - -
@sentry/browser (incl. Metrics) 28.86 kB - -
@sentry/browser (incl. Logs) 29.09 kB - -
@sentry/browser (incl. Metrics & Logs) 29.79 kB - -
@sentry/react 29.57 kB - -
@sentry/react (incl. Tracing) 48.89 kB - -
@sentry/vue 33.21 kB - -
@sentry/vue (incl. Tracing) 48.58 kB - -
@sentry/svelte 27.8 kB - -
CDN Bundle 30.12 kB - -
CDN Bundle (incl. Tracing) 48.5 kB - -
CDN Bundle (incl. Logs, Metrics) 31.7 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 49.8 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 70.96 kB - -
CDN Bundle (incl. Tracing, Replay) 86.01 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 87.33 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 91.82 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 93.08 kB - -
CDN Bundle - uncompressed 89.75 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.63 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 94.47 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 150.61 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 219.23 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 265.87 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 269.83 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.57 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 283.53 kB - -
@sentry/nextjs (client) 51.4 kB - -
@sentry/sveltekit (client) 47.03 kB - -
@sentry/core/server 80.14 kB - -
@sentry/core/browser 51.99 kB - -
@sentry/node 124.27 kB +0.01% +1 B 🔺
@sentry/node (incl. diagnostics channel injection) 149.7 kB +0.01% +1 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 70.03 kB - -
@sentry/node - without tracing 74.44 kB +0.01% +2 B 🔺
@sentry/aws-serverless 83.92 kB - -
@sentry/cloudflare (withSentry) - minified 197.81 kB +0.6% +1.17 kB 🔺
@sentry/cloudflare (withSentry) 486.75 kB +0.59% +2.83 kB 🔺

View base workflow run

- Fix spotlight precedence to match node-core's getSpotlightConfig:
  spotlight: true + env URL → uses env URL (not bare true)
- Fix accidental extra-space indent on instrumentPrototypeMethods
- Add tests: spotlight:true + env URL, 4xx/5xx status handling
@MathurAditya724
MathurAditya724 requested a review from BYK July 22, 2026 12:44
@MathurAditya724
MathurAditya724 marked this pull request as ready for review July 22, 2026 12:48
@MathurAditya724
MathurAditya724 requested a review from a team as a code owner July 22, 2026 12:48
@MathurAditya724
MathurAditya724 requested review from JPeer264 and isaacs and removed request for a team July 22, 2026 12:48
…ght wiring

The rollup-include-development-only markers only strip content when the
package build uses splitDevProd (only @sentry/browser does). The Cloudflare
package uses a single build without that plugin, so the markers were inert
and misleading. Match the node-core pattern: guard spotlight wiring with the
runtime 'if (options.spotlight)' check, which is falsy in production.
@timfish

timfish commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Spotlight forwarding only activates when options.spotlight is truthy, which is falsy in production by default

I had a quick look through the code so I might have missed it but how does options.spotlight end up falsy in prod by default?

identical to how @sentry/node, and all other server SDKs ship the spotlight integration

This is not true. The Node SDK specifically ship dev/prod output and strips this from production builds.

@timfish

timfish commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

This is not true. The Node SDK specifically ship dev/prod output and strips this from production builds

I was wrong, we only do this in the browser:

/*! rollup-include-development-only */
if (options.spotlight) {
if (!defaultIntegrations) {
defaultIntegrations = [];
}
const args = typeof options.spotlight === 'string' ? { sidecarUrl: options.spotlight } : undefined;
defaultIntegrations.push(spotlightBrowserIntegration(args));
}
/*! rollup-include-development-only-end */

@JPeer264

Copy link
Copy Markdown
Member

I was wrong, we only do this in the browser:

Ya, I just went through and we only have this in the browser. @timfish if I'm not mistaken we only have to add splitDevProd in the rollup config and change the exports right?

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.

3 participants