sentry-javascript icon indicating copy to clipboard operation
sentry-javascript copied to clipboard

Sentry Cloudflare Workers SDK

Open AbhiPrasad opened this issue 1 year ago • 19 comments

ref https://github.com/getsentry/sentry-javascript/issues/2484 ref https://github.com/getsentry/sentry-javascript/issues/5611

Let's add some 1st class cloudflare workers support (finally)!

We've had https://github.com/robertcepa/toucan-js for a while that has worked great, but doesn't match our unified API and doesn't have full support for performance, cron monitoring, and more.

First we can start off by making a basic package, @sentry/cloudflare-workers

### Initial
- [ ] https://github.com/getsentry/sentry-javascript/issues/12685
- [ ] https://github.com/getsentry/sentry-javascript/pull/12953
- [ ] https://github.com/getsentry/sentry-javascript/pull/13025
- [ ] https://github.com/getsentry/sentry-javascript/pull/13087
- [ ] https://github.com/getsentry/sentry-javascript/pull/13096
### After First Release
- [ ] https://github.com/getsentry/sentry-javascript/issues/13111
- [ ] https://github.com/getsentry/platformicons/issues/173
- [ ] https://github.com/getsentry/sentry-release-registry/pull/164
- [ ] https://github.com/getsentry/sentry-javascript/pull/13206
- [ ] Add wizard command to setup cloudflare workers sdk
- [ ] Add cloudflare workers to sentry onboarding
- [ ] Ensure distributed tracing between cloudflare workers
- [ ] Publish docs for cloudflare workers package
- [ ] Add version metadata https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/

Once the SDK is in a good state we can think about better instrumentation for the different bindings that cloudflare workers exposes. Top of mind is:

### Bindings support
- [ ] https://github.com/getsentry/sentry-javascript/issues/13141
- [ ] Add cloudflare queues instrumentation https://developers.cloudflare.com/queues/configuration/javascript-apis/
- [ ] Add r2 instrumentation https://developers.cloudflare.com/r2/api/workers/workers-api-reference/
- [ ] Add kv instrumentation https://developers.cloudflare.com/kv/
- [ ] Add durable objects instrumentation

At the same time we should make sure that we add support for our metaframeworks to use the Cloudflare workers SDK

### Support metaframeworks
- [ ] https://github.com/getsentry/sentry-javascript/pull/13123
- [ ] https://github.com/getsentry/sentry-javascript/issues/5610
- [ ] https://github.com/getsentry/sentry-javascript/issues/8291
- [ ] https://github.com/getsentry/sentry-javascript/issues/11920
- [ ] Astro
- [ ] Nuxt
- [ ] SolidStart
- [ ] Next.js (https://github.com/getsentry/sentry-javascript/issues/11920)

AbhiPrasad avatar Jun 24 '24 15:06 AbhiPrasad

Initial thinking of the general API.

We're probably only going to support ES modules syntax.

Current toucan requires you to always instantiate new Toucan. Ideally we can avoid this by exposing a helper that wraps export default obj from the entry point.

It would probably automatically try to read env.SENTRY_DSN to get the sentry dsn.

export default withSentry({ beforeSend }, {
  async fetch(request, env, ctx) {
    return new Response('Hello World!');
  },
});

For further customization, you can take a function withSentryHandler that isolates sentry to the specific handler you care about. This allows you to override how sentry is initialized for that specific handler without

export default withSentry({ tracesSampleRate: 1.0 }, {
  async fetch: withSentryFetchHandler((init) => (request, env, ctx) => {
    const client = init({ tracesSampleRate: 0.5, request, env, ctx });
    // do whatever you want with client
    return new Response('Hello World!');
  }),
});

With the withSentry API's you'll need to have compatibility_flags = [ "nodejs_als" ] on in your wrangler.toml, otherwise you risk request bleeding (we require AsyncLocalStorage to do isolation).

If you don't want any node_compat, we can't do the global withSentry magic function, so you'll need to manually create a client.

import * as Sentry from '@sentry/cloudflare-workers';

export default {
  async fetch(request, env, ctx) {
    const client = new Sentry.CloudflareWorkersClient();
    const scope = new Sentry.Scope();
    scope.setClient(client);

    try {
      handler();
      return new Response('Hello!');
    } catch (e) {
      scope.captureException(e);

      return new Response('Something went wrong! Team has been notified.', {
        status: 500,
      });
    }
  },
};

Unfortunately performance is not active here because the parent child relationship is wrong, so maybe we gate performance behind requiring compatibility_flags = [ "nodejs_als" ]. The same also applies for automatic instrumentation adding breadcrumbs, we risk attaching to the wrong request. All automatic instrumentation (like automatically instrumenting d1 or r2 bindings) might be turned off if we cannot access asynclocalstorage.

We also need to add support for Version metadata binding - I'm imagining this is easiest to expose as an init config where you tell us what environmental variable to access for this info, and we automatically update releases and such.

AbhiPrasad avatar Jun 24 '24 21:06 AbhiPrasad

I'm throwing around some experiments in https://github.com/AbhiPrasad/sentry-cloudflare-test/tree/main/examples

AbhiPrasad avatar Jun 26 '24 00:06 AbhiPrasad

Hey @AbhiPrasad,

by adding support for Cloudflare Workers, do you also plan to add support for Cloudflare Pages? I know CF are working on unifying the two platforms, but it's still "a bit out there" (at least according to their Discord) and there are some subtle differences to how they work.

Anyways, awesome that you are doing this! 😄 I've been looking forward to official support for a long time!

ChristianJacobsen avatar Jun 26 '24 09:06 ChristianJacobsen

by adding support for Cloudflare Workers, do you also plan to add support for Cloudflare Pages

Yes for sure, this is def part of it because this is how all the metaframework integrations work. Let me make it more clear in the tracking issue, and also add some example of API design for that too.

AbhiPrasad avatar Jun 26 '24 13:06 AbhiPrasad

[...] how all the Metaframework integrations work

Does this include Astro? 👀 I know there is already an @sentry/astro integration (which is great), but the Cloudflare adapter (and Astro in SSR mode) is still not supported with it.

Like everyone else said, im also super happy that this is being worked on :)

F0rce avatar Jun 27 '24 19:06 F0rce

Does this include Astro

Yes! At the beginning you might have to manually add @sentry/cloudflare-workers yourself (and wrap some methods accordingly), but we'll work toward it all being automatically setup.

AbhiPrasad avatar Jun 27 '24 20:06 AbhiPrasad

  • Add durable objects instrumentation

Durable objects run in a separate isolate with their own fetch function. Would you use withSentry here?

Cloudflare workers also has:

  • Service Bindings for calling other workers - https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/
  • RPC between workers - https://developers.cloudflare.com/workers/runtime-apis/rpc/#remote-procedure-call-rpc

It would be great to have tracing work across all these boundaries too!

timfish avatar Jul 29 '24 10:07 timfish

Durable objects run in a separate isolate with their own fetch function. Would you use withSentry here?

We need a different exported method.

It would be great to have tracing work across all these boundaries too!

Adding to the todo!

AbhiPrasad avatar Jul 29 '24 13:07 AbhiPrasad

Hi everyone! Good news - we have something for everyone to try out now!

Say hello to @sentry/cloudflare - available in 8.22.0 and above.

The README has all the details: https://github.com/getsentry/sentry-javascript/blob/develop/packages/cloudflare/README.md (although now I see the README says the package is unreleased, need to fix that 😅).

AbhiPrasad avatar Aug 01 '24 14:08 AbhiPrasad

Is there any way to apply multiple plugin at now? For example, I want to deploy Sveltekit website on Cloudflare Pages, then I have to use both @sentry/sveltekit and @sentry/cloudflare and it not makes sense.

seo-rii avatar Aug 04 '24 15:08 seo-rii

Hey @seo-rii I'm not a CF expert but are you getting any specific errors with both @sentry/sveltekit and @sentry/cloudflare?

We might tighten the integration a bit in the future but what I'd recommend trying for now is to call Sentry.init() from @sentry/cloudflare in your hooks.server.ts file and use @sentry/sveltekit for the client side (hooks.client.ts).

Lms24 avatar Aug 06 '24 07:08 Lms24

Hey @seo-rii I'm not a CF expert but are you getting any specific errors with both @sentry/sveltekit and @sentry/cloudflare?

We might tighten the integration a bit in the future but what I'd recommend trying for now is to call Sentry.init() from @sentry/cloudflare in your hooks.server.ts file and use @sentry/sveltekit for the client side (hooks.client.ts).

It works great! I was mistaking this for not working, which was due to another bug(#8291) that was happening when creating the source map. 😢

seo-rii avatar Aug 09 '24 05:08 seo-rii

@seo-rii I couldn't get it to work no matter what I do. Were you able to get past that error?

I did

  ssr: {
    noExternal: ['@sentry/sveltekit']
  }

Which brought me into a different hell with node modules such as fs not being supported in Cloudflare eventhough node_compat is active.

BYK avatar Aug 12 '24 11:08 BYK

Alternatively, I get the following:

/home/byk/Projects/<my project>/node_modules/wrangler/wrangler-dist/cli.js:29573
            throw a;
            ^
file:///home/byk/Projects/<my project>/.svelte-kit/output/server/chunks/index.server.js:12
import require$$0 from "@sentry/utils";
       ^^^^^^^^^^
SyntaxError: The requested module '@sentry/utils' does not provide an export named 'default'

BYK avatar Aug 12 '24 11:08 BYK

For folks using astro, I successful got this integrated into my site. I wrote an astro integration, but it's not quite packaged up to be published yet. The code can be found here: https://github.com/zephraph/just-be.dev/tree/67248eaa2a4edbe7c69840227de236aa72beb41c/packages/astro-cf-sentry. I'm happy to answer questions or help others if I can.

just-be-dev avatar Aug 13 '24 01:08 just-be-dev

@BYK I just removed plugin from vite config. It seems sourcemap generation does not working properly at now.

seo-rii avatar Aug 13 '24 02:08 seo-rii

Followed the guide, working with SvelteKit and adapter-cloudflare. Getting this error:

TypeError: Cannot read properties of undefined (reading 'waitUntil')

Am I missing something obvious here?

EDIT:

I cleared some temp files/folders such as .wrangler pnpm lock file, node_modules, and the error is no longer present - ugh sometimes I hate JS development package managing/bundling lol.

saturnonearth avatar Aug 14 '24 06:08 saturnonearth

Hey,

I am trying to use Sentry.metrics.increment("email_send", 1); in a pages functions. This syntax works in the react frontend, but that function doesnt exist in the cloudflare SDK and instead there is only one that requires a MetricsAggregatorConstructor param. In the SDK source code for the browser package, it looks like its importing the BrowserMetricsAggregator, adding that to the function args, and then wrapping that with a function without that aggregator thing.

Image

I tried doing the same within my project, but I am not seeing the metric being logged.

Any help would be greatly appreciated. Thanks!

KyGuy2002 avatar Aug 21 '24 05:08 KyGuy2002

Hey @KyGuy2002, we're currently on company-wide hackweek and thus on limited support. We'll take a look at this next week.

andreiborza avatar Aug 21 '24 07:08 andreiborza

Hey @KyGuy2002, we're currently on company-wide hackweek and thus on limited support. We'll take a look at this next week.

Hey, I'm sure you are very busy but let me know if you need anything else from me to help with this issue. Thanks!

KyGuy2002 avatar Sep 03 '24 01:09 KyGuy2002

Hey, sorry there hasn't been an update yet. We're having some people out of office, but this should get picked up soon/this week.

andreiborza avatar Sep 03 '24 01:09 andreiborza

No worries, thanks for the update 👍

KyGuy2002 avatar Sep 03 '24 01:09 KyGuy2002

Hi all, it's great to see Cloudflare Workers getting some attention. Cloudflare seem to be moving towards the WorkerEntrypoint/class-based approach. E.g., RPC methods (worker-to-worker requests) are only supported with WorkerEntrypoint: https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/rpc/#the-workerentrypoint-class

Are there plans to support this structure?

CameronB15 avatar Apr 01 '25 12:04 CameronB15

@CameronB15 I created https://github.com/getsentry/sentry-javascript/issues/15942 to track this!

AbhiPrasad avatar Apr 01 '25 12:04 AbhiPrasad