From 14ca7b6ed95156c336b2d8a66cacc258a4809a4c Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:50:03 -0500 Subject: [PATCH] docs: add sentry integration docs (#21439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: add sentry integration docs * feat: add sentry edge functions monitoring guide. * feat: add sentry functions example. * fix: navbar. * chore: nits. * chore: add to functions example list. * fix: formatting. * chore: add nextjs example. * fix: rename sentry guide * remove configuration options * Apply suggestions from code review Co-authored-by: Kamil Ogórek --------- Co-authored-by: thorwebdev Co-authored-by: Thor 雷神 Schaeff <5748289+thorwebdev@users.noreply.github.com> Co-authored-by: Kamil Ogórek --- .../NavigationMenu.constants.ts | 15 +- apps/docs/content/guides/functions.mdx | 5 + .../functions/examples/sentry-monitoring.mdx | 80 ++++++ .../guides/platform/sentry-monitoring.mdx | 265 ++++++++++++++++++ .../supabase/functions/sentryfied/index.ts | 32 +++ 5 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 apps/docs/content/guides/functions/examples/sentry-monitoring.mdx create mode 100644 apps/docs/content/guides/platform/sentry-monitoring.mdx create mode 100644 examples/edge-functions/supabase/functions/sentryfied/index.ts diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index ff46f23d71c..06159558a90 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -1201,6 +1201,10 @@ export const functions: NavMenuConstant = { name: 'Hugging Face', url: '/guides/ai/examples/huggingface-image-captioning', }, + { + name: 'Monitoring with Sentry', + url: '/guides/functions/examples/sentry-monitoring', + }, { name: 'OpenAI API', url: '/guides/ai/examples/openai' }, { name: 'Sending Emails with Resend', @@ -1593,6 +1597,15 @@ export const platform: NavMenuConstant = { { name: 'Read Replicas', url: '/guides/platform/read-replicas' }, ], }, + { + name: 'Logging and observability', + url: undefined, + items: [ + { name: 'Logging', url: '/guides/platform/logs' }, + { name: 'Metrics', url: '/guides/platform/metrics' }, + { name: 'Monitoring with Sentry', url: '/guides/platform/sentry-monitoring' }, + ], + }, { name: 'Platform Management', url: undefined, @@ -1608,8 +1621,6 @@ export const platform: NavMenuConstant = { name: 'HTTP Status Codes', url: '/guides/platform/http-status-codes', }, - { name: 'Logging', url: '/guides/platform/logs' }, - { name: 'Metrics', url: '/guides/platform/metrics' }, { name: 'Migrating and Upgrading', url: '/guides/platform/migrating-and-upgrading-projects', diff --git a/apps/docs/content/guides/functions.mdx b/apps/docs/content/guides/functions.mdx index 4889ef00ef0..a326898f1b5 100644 --- a/apps/docs/content/guides/functions.mdx +++ b/apps/docs/content/guides/functions.mdx @@ -37,6 +37,11 @@ Check out the [Edge Function Examples](https://github.com/supabase/supabase/tree 'Combining Kysely with Deno Postgres gives you a convenient developer experience for interacting directly with your Postgres database.', href: '/guides/functions/kysely-postgres', }, + { + name: 'Monitoring with Sentry', + description: 'Monitor Edge Functions with the Sentry Deno SDK.', + href: '/guides/functions/examples/sentry-monitoring', + }, { name: 'With CORS headers', description: 'Send CORS headers for invoking from the browser.', diff --git a/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx b/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx new file mode 100644 index 00000000000..3571c5108dd --- /dev/null +++ b/apps/docs/content/guides/functions/examples/sentry-monitoring.mdx @@ -0,0 +1,80 @@ +--- +title: 'Monitoring with Sentry' +description: 'Monitor Edge Functions with the Sentry Deno SDK.' +--- + +Add the [Sentry Deno SDK](https://docs.sentry.io/platforms/javascript/guides/deno/) to your Supabase Edge Functions to easily track exceptions and get notified of errors or performance issues. + +### Prerequisites + +- [Create a Sentry account](https://sentry.io/signup/). +- Make sure you have the latest version of the [Supabase CLI](https://supabase.com/docs/guides/cli#installation) installed. + +### 1. Create Supabase function + +Create a new function locally: + +```bash +supabase functions new sentryfied +``` + +### 2. Add the Sentry Deno SDK + +Handle exceptions within your function and send them to Sentry. + +```tsx +import * as Sentry from 'https://deno.land/x/sentry/index.mjs' + +Sentry.init({ + // https://docs.sentry.io/product/sentry-basics/concepts/dsn-explainer/#where-to-find-your-dsn + dsn: SENTRY_DSN, + defaultIntegrations: false, + // Performance Monitoring + tracesSampleRate: 1.0, + // Set sampling rate for profiling - this is relative to tracesSampleRate + profilesSampleRate: 1.0, +}) + +// Set region and execution_id as custom tags +Sentry.setTag('region', Deno.env.get('SB_REGION')) +Sentry.setTag('execution_id', Deno.env.get('SB_EXECUTION_ID')) + +Deno.serve(async (req) => { + try { + const { name } = await req.json() + // This will throw, as `name` in our example call will be `undefined` + const data = { + message: `Hello ${name}!`, + } + + return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } }) + } catch (e) { + Sentry.captureException(e) + return new Response(JSON.stringify({ msg: 'error' }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }) + } +}) +``` + +### 3. Deploy and test + +Run function locally: + +```bash +supabase start +supabase functions serve --no-verify-jwt +``` + +Test it: http://localhost:54321/functions/v1/sentryfied + +Deploy function to Supabase: + +```bash +supabase functions deploy sentryfied --no-verify-jwt +``` + +### 4. Try it yourself + +Find the complete example on [GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/sentryfied/index.ts). diff --git a/apps/docs/content/guides/platform/sentry-monitoring.mdx b/apps/docs/content/guides/platform/sentry-monitoring.mdx new file mode 100644 index 00000000000..af75d8cc7e9 --- /dev/null +++ b/apps/docs/content/guides/platform/sentry-monitoring.mdx @@ -0,0 +1,265 @@ +--- +title: 'Sentry integration' +subtitle: 'Integrate Sentry to monitor errors from a Supabase client' +--- + +You can use [Sentry](https://sentry.io/welcome/) to monitor errors thrown from a Supabase JavaScript client. Install the [Supabase Sentry integration](https://github.com/supabase-community/sentry-integration-js) to get started. + +The Sentry integration supports browser, Node, and edge environments. + +## Installation + +Install the Sentry integration using your package manager: + + + + + +```sh +npm install @supabase/sentry-js-integration +``` + + + + + +```sh +yarn add @supabase/sentry-js-integration +``` + + + + + +```sh +pnpm add @supabase/sentry-js-integration +``` + + + + + +## Use + +To use the Supabase Sentry integration, add it to your `integrations` list when initializing your Sentry client. + +You can supply either the Supabase Client constructor or an already-initiated instance of a Supabase Client. + + + + + +```ts +import * as Sentry from '@sentry/browser' +import { SupabaseClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + new SupabaseIntegration(SupabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + ], +}) +``` + + + + + +```ts +import * as Sentry from '@sentry/browser' +import { createClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY) + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + new SupabaseIntegration(supabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + ], +}) +``` + + + + + +## Deduplicating spans + +If you're already monitoring HTTP errors in Sentry, for example with the Http, Fetch, or Undici integrations, you will get duplicate spans for Supabase calls. You can deduplicate the spans by skipping them in your other integration: + +```ts +import * as Sentry from '@sentry/browser' +import { SupabaseClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + new SupabaseIntegration(SupabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + + // @sentry/browser + new Sentry.BrowserTracing({ + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${SUPABASE_URL}/rest`) + }, + }), + + // or @sentry/node + new Sentry.Integrations.Http({ + tracing: { + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${SUPABASE_URL}/rest`) + }, + }, + }), + + // or @sentry/node with Fetch support + new Sentry.Integrations.Undici({ + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${SUPABASE_URL}/rest`) + }, + }), + + // or @sentry/WinterCGFetch for Next.js Middleware & Edge Functions + new Sentry.Integrations.WinterCGFetch({ + breadcrumbs: true, + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${SUPABASE_URL}/rest`) + }, + }), + ], +}) +``` + +## Example Next.js configuration + +See this example for a setup with Next.js to cover browser, server, and edge environments. First, run through the [Sentry Next.js wizard](https://docs.sentry.io/platforms/javascript/guides/nextjs/#install) to generate the base Next.js configuration. Then add the Supabase Sentry Integration to all your `Sentry.init` calls with the appropriate filters. + + + + + +```ts sentry.client.config.ts +import * as Sentry from '@sentry/nextjs' +import { SupabaseClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +Sentry.init({ + dsn: SENTRY_DSN, + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: true, + + replaysOnErrorSampleRate: 1.0, + + // This sets the sample rate to be 10%. You may want this to be 100% while + // in development and sample at a lower rate in production + replaysSessionSampleRate: 0.1, + + // You can remove this option if you're not planning to use the Sentry Session Replay feature: + integrations: [ + Sentry.replayIntegration({ + // Additional Replay configuration goes in here, for example: + maskAllText: true, + blockAllMedia: true, + }), + new SupabaseIntegration(SupabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + new Sentry.BrowserTracing({ + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest`) + }, + }), + ], +}) +``` + + + + + +```ts sentry.server.config.ts +import * as Sentry from '@sentry/nextjs' +import { SupabaseClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + new SupabaseIntegration(SupabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + new Sentry.Integrations.Undici({ + shouldCreateSpanForRequest: (url) => { + console.log('server', `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest`, url) + return !url.startsWith(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest`) + }, + }), + ], + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: true, +}) +``` + + + + + +```js sentry.edge.config.ts +import * as Sentry from '@sentry/nextjs' +import { SupabaseClient } from '@supabase/supabase-js' +import { SupabaseIntegration } from '@supabase/sentry-js-integration' + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + new SupabaseIntegration(SupabaseClient, { + tracing: true, + breadcrumbs: true, + errors: true, + }), + new Sentry.Integrations.WinterCGFetch({ + breadcrumbs: true, + shouldCreateSpanForRequest: (url) => { + return !url.startsWith(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest`) + }, + }), + ], + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + // Setting this option to true will print useful information to the console while you're setting up Sentry. + debug: true, +}) +``` + + + + + +Afterward build your application (`npm run build`) and start it locally (`npm run start`). You will now see the transactions being logged in the terminal when making supabase-js requests. diff --git a/examples/edge-functions/supabase/functions/sentryfied/index.ts b/examples/edge-functions/supabase/functions/sentryfied/index.ts new file mode 100644 index 00000000000..4715db7a0d4 --- /dev/null +++ b/examples/edge-functions/supabase/functions/sentryfied/index.ts @@ -0,0 +1,32 @@ +import * as Sentry from 'https://deno.land/x/sentry/index.mjs' + +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [], + debug: true, + // Performance Monitoring + tracesSampleRate: 1.0, + // Set sampling rate for profiling - this is relative to tracesSampleRate + profilesSampleRate: 1.0, +}) + +// Set region and execution_id as custom tags +Sentry.setTag('region', Deno.env.get('SB_REGION')) +Sentry.setTag('execution_id', Deno.env.get('SB_EXECUTION_ID')) + +Deno.serve(async (req) => { + try { + const { name } = await req.json() + const data = { + message: `Hello ${name}!`, + } + + return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } }) + } catch (e) { + Sentry.captureException(e) + return new Response(JSON.stringify({ msg: 'error' }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }) + } +})