getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.9k stars 1.56k forks source link

Sentry Cloudflare Workers SDK #12620

Open AbhiPrasad opened 3 months ago

AbhiPrasad commented 3 months ago

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 commented 3 months ago

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 commented 3 months ago

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

ChristianJacobsen commented 3 months ago

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!

AbhiPrasad commented 3 months ago

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.

F0rce commented 3 months ago

[...] 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 :)

AbhiPrasad commented 3 months ago

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.

timfish commented 2 months ago

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

Cloudflare workers also has:

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

AbhiPrasad commented 2 months ago

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 commented 2 months ago

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 πŸ˜…).

seo-rii commented 1 month ago

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.

Lms24 commented 1 month ago

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

seo-rii commented 1 month ago

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

BYK commented 1 month ago

@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 commented 1 month ago

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'
zephraph commented 1 month ago

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.

seo-rii commented 1 month ago

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

saturnonearth commented 1 month ago

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.

KyGuy2002 commented 1 month ago

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!

andreiborza commented 1 month ago

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

KyGuy2002 commented 4 weeks ago

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!

andreiborza commented 4 weeks ago

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.

KyGuy2002 commented 4 weeks ago

No worries, thanks for the update πŸ‘