Skip to content

Commit

Permalink
Improved API, better types, updated readme, screenshots
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilogorek committed Dec 4, 2023
1 parent 1a0a1d5 commit 6e543c3
Show file tree
Hide file tree
Showing 18 changed files with 136 additions and 35 deletions.
111 changes: 96 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset="supabase-wordmark--dark.svg">
<source media="(prefers-color-scheme: light)" srcset="supabase-wordmark--light.svg">
<img alt="Supabase logo" src="supabase-wordmark--dark.svg" width="256">
</picture>

<picture>
<source media="(prefers-color-scheme: dark)" srcset="sentry-wordmark--dark.svg">
<source media="(prefers-color-scheme: light)" srcset="sentry-wordmark--light.svg">
<img alt="Sentry logo" src="sentry-wordmark--dark.svg" width="256">
</picture>
<br/>

<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="logos/supabase-wordmark--dark.svg">
<source media="(prefers-color-scheme: light)" srcset="logos/supabase-wordmark--light.svg">
<img alt="Supabase logo" src="logos/supabase-wordmark--dark.svg" width="320">
</picture>
<br />
<picture>
<source media="(prefers-color-scheme: dark)" srcset="logos/sentry-wordmark--dark.svg">
<source media="(prefers-color-scheme: light)" srcset="logos/sentry-wordmark--light.svg">
<img alt="Sentry logo" src="logos/sentry-wordmark--dark.svg" width="256">
</picture>
</p>

# @supabase/sentry-js-integration

Sentry JavaScript SDK Integration that can be used to instrument Supabase JavaScript SDK instrumentation.
Sentry JavaScript SDK Integration that can be used to instrument Supabase JavaScript SDK and collect traces, breadcrumbs and errors.

See [Showcase](#showcase) section for detailed screenshots of what is captured.

## Install

Expand Down Expand Up @@ -44,6 +50,81 @@ Sentry.init({
- `breadcrumbs: boolean` - Enable capturing breadcrumbs for database calls _(defaults to **true**)_
- `errors: boolean` - Enable capturing non-throwable database errors as Sentry exceptions _(defaults to **false**)_
- `operations: "select" | insert" | "upsert" | "update" | "delete"` - Configures which methods should be instrumented for the features above _(defaults to **all operations**)_
- `shouldCreateSpan: (builder) => boolean` - Decide whether a span should be created based on the query builder used to capture this data
- `shouldCreateBreadcrumb: (builder) => boolean` - Decide whether a breadcrumb should be created based on the query builder used to capture this data
- `sanitizeBody: (key, value) => value` - Allows for modifying captured body values that are passed to `insert/upsert/update` operations, before assigned to a `span`, `breadcrumb`, or `error
- `shouldCreateSpan: (payload) => boolean` - Decide whether a span should be created based on the query payload used to capture this data
- `shouldCreateBreadcrumb: (payload) => boolean` - Decide whether a breadcrumb should be created based on the query payload used to capture this data
- `sanitizeBody: (table, key, value) => value` - Allows for modifying captured body values that are passed to `insert/upsert/update` operations, before assigned to a `span`, `breadcrumb`, or `error

### Removing duplicated http/fetch spans

If you are using built-in `Http`, `Fetch` or `Undici` integrations in your current Sentry setup, you might want to skip some of the spans that will be already covered by `SupabaseIntegration`. Here's a quick snippet how to do that:

```js
// @sentry/browser
new Sentry.BrowserTracing({
shouldCreateSpanForRequest: (url) => {
return !url.startsWith(SUPABASE_URL);
},
});

// or @sentry/node
new Sentry.Integrations.Http({
tracing: {
shouldCreateSpanForRequest: (url) => {
return !url.startsWith(SUPABASE_URL);
},
},
});

// or @sentry/node with Fetch support
new Sentry.Integrations.Undici({
shouldCreateSpanForRequest: (url) => {
return !url.startsWith(SUPABASE_URL);
},
});
```

## Showcase

_(click to enlarge image)_

### Server-side Traces

<table>
<tr>
<td valign="top"><img src="screenshots/server-side.png" width="320"></td>
<td valign="top"><img src="screenshots/server-side-details.png" width="320"></td>
</tr>
</table>

### Client-side Traces

<table>
<tr>
<td valign="top"><img src="screenshots/client-side.png" width="320"></td>
<td valign="top"><img src="screenshots/client-side-details.png" width="320"></td>
</tr>
</table>

### Capturing Non-throwable Errors

<table>
<tr>
<td valign="top"><img src="screenshots/errors.png" width="320"></td>
</tr>
</table>

### Breadcrumbs

<table>
<tr>
<td valign="top"><img src="screenshots/breadcrumbs.png" width="320"></td>
</tr>
</table>

### Payload Sanitization

<table>
<tr>
<td valign="top"><img src="screenshots/body-sanitization.png" width="320"></td>
</tr>
</table>
39 changes: 26 additions & 13 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type SupabaseClient } from "@supabase/supabase-js";
import { type PostgrestBuilder } from "@supabase/postgrest-js";
import { SupabaseClient } from "@supabase/supabase-js";
import { EventProcessor, Hub, Integration } from "@sentry/types";

/**
@returns Sentry JavaScript SDK Integration that can be used to instrument Supabase JavaScript SDK instrumentation.
Expand All @@ -21,17 +21,30 @@ Sentry.init({
});
```
*/
export class SupabaseIntegration {
export class SupabaseIntegration implements Integration {
name: string;
constructor(
clientConstructor: SupabaseClient,
options: {
tracing?: boolean;
errors?: boolean;
breadcrumbs?: boolean;
operations?: ["select" | "insert" | "upsert" | "update" | "delete"][];
shouldCreateSpan: (builder: PostgrestBuilder<unknown>) => boolean;
shouldCreateBreadcrumb: (builder: PostgrestBuilder<unknown>) => boolean;
sanitizeBody(key: string, value: unknown): any;
}
clientConstructor: typeof SupabaseClient,
options?: Partial<{
tracing: boolean;
errors: boolean;
breadcrumbs: boolean;
operations: ["select" | "insert" | "upsert" | "update" | "delete"][];
shouldCreateSpan: (payload: Payload) => boolean;
shouldCreateBreadcrumb: (payload: Payload) => boolean;
sanitizeBody(table: string, key: string, value: unknown): any;
}>
);
setupOnce(
addGlobalEventProcessor: (callback: EventProcessor) => void,
getCurrentHub: () => Hub
): void;
}

export type Payload = {
method: "GET" | "HEAD" | "POST" | "PATCH" | "DELETE";
url: URL;
headers: Record<string, string>;
schema?: string;
body?: unknown;
};
14 changes: 11 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,22 @@ export class SupabaseIntegration {
for (const [key, value] of Object.entries(thisArg.body)) {
body[key] =
typeof self.options.sanitizeBody === "function"
? self.options.sanitizeBody(key, value)
? self.options.sanitizeBody(table, key, value)
: value;
}
}

const shouldCreatePayload = {
method: thisArg.method,
url: thisArg.url,
headers: thisArg.headers,
schema: thisArg.schema,
body: thisArg.body,
};

const shouldCreateSpan =
typeof self.options.shouldCreateSpan === "function"
? self.options.shouldCreateSpan(thisArg)
? self.options.shouldCreateSpan(shouldCreatePayload)
: true;

let span;
Expand Down Expand Up @@ -341,7 +349,7 @@ export class SupabaseIntegration {

const shouldCreateBreadcrumb =
typeof self.options.shouldCreateBreadcrumb === "function"
? self.options.shouldCreateBreadcrumb(thisArg)
? self.options.shouldCreateBreadcrumb(shouldCreatePayload)
: true;

if (self.options.breadcrumbs && shouldCreateBreadcrumb) {
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"@supabase/supabase-js": "2.x"
},
"devDependencies": {
"@supabase/postgrest-js": "^1.9.0",
"@supabase/supabase-js": "2.39.0"
}
}
Binary file added screenshots/body-sanitization.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/breadcrumbs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/client-side-details.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/client-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/errors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/server-side-details.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/server-side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/breadcrumbs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ test("Breadcrumbs", async (t) => {
(integration = new SupabaseIntegration(Supabase.SupabaseClient, {
breadcrumbs: true,
errors: true,
sanitizeBody(key, value) {
sanitizeBody(table, key, value) {
switch (key) {
case "password":
return "<redacted>";
Expand Down
2 changes: 1 addition & 1 deletion tests/errors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ test("Errors", async (t) => {
const { captureException } = initSentry(
(integration = new SupabaseIntegration(Supabase.SupabaseClient, {
errors: true,
sanitizeBody(key, value) {
sanitizeBody(table, key, value) {
switch (key) {
case "password":
return "<redacted>";
Expand Down
2 changes: 1 addition & 1 deletion tests/tracing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ test("Tracing", async (t) => {
);
const { setHttpStatus, finish, startChild } = initSentry(
(integration = new SupabaseIntegration(Supabase.SupabaseClient, {
sanitizeBody(key, value) {
sanitizeBody(table, key, value) {
switch (key) {
case "password":
return "<redacted>";
Expand Down

0 comments on commit 6e543c3

Please sign in to comment.