Skip to content

Added Sentry example #1435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions docs/guides/examples/sentry-error-tracking.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
title: "Track errors with Sentry"
sidebarTitle: "Sentry error tracking"
description: "This example demonstrates how to track errors with Sentry using Trigger.dev."
---

## Overview

Automatically send errors to your Sentry project from your Trigger.dev tasks.

## Prerequisites

- A [Sentry](https://sentry.io) account and project
- A [Trigger.dev](https://trigger.dev) account and project

## Build configuration

To send errors to Sentry when there are errors in your tasks, you'll need to add this build configuration to your `trigger.config.ts` file. This will then run every time you deploy your project.

<Note>
Make sure you use the correct sentry package for your runtime. For example, if you are using
Node.js, you should use the `@sentry/node` package. For a full list of supported packages, see the
[Sentry docs](https://docs.sentry.io/platforms/).
</Note>

<Note>
You will need to set the `SENTRY_AUTH_TOKEN` and `SENTRY_DSN` environment variables. You can find
the `SENTRY_AUTH_TOKEN` in your Sentry dashboard, in settings -> developer settings -> auth tokens
and the `SENTRY_DSN` in your Sentry dashboard, in settings -> projects -> your project -> client
keys (DSN). Add these to your `.env` file, and in your [Trigger.dev
dashboard](https://cloud.trigger.dev), under environment variables in your project's sidebar.
</Note>

```ts trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk/v3";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
// Import the correct Sentry package for your runtime, e.g. @sentry/node for Node.js or @Sentry/nextjs for Next.js
import * as Sentry from "@sentry/node";

export default defineConfig({
project: "<project ref>",
// Your other config settings...
build: {
extensions: [
additionalPackages({
// Add the correct Sentry package for your runtime, e.g. @sentry/node for Node.js or @Sentry/nextjs for Next.js
packages: ["@sentry/node"],
}),
esbuildPlugin(
sentryEsbuildPlugin({
org: "<your-sentry-org>",
project: "<your-sentry-project>",
// Find this auth token in settings -> developer settings -> auth tokens
authToken: process.env.SENTRY_AUTH_TOKEN,
}),
// Optional - only runs during the deploy command, and adds the plugin to the end of the list of plugins
{ placement: "last", target: "deploy" }
),
],
},
init: async () => {
Sentry.init({
// The Data Source Name (DSN) is a unique identifier for your Sentry project.

dsn: process.env.SENTRY_DSN,
// Update this to match the environment you want to track errors for
environment: process.env.NODE_ENV === "production" ? "production" : "development",
});
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling to the init function.

The initialization could fail silently if environment variables are missing.

 init: async () => {
+  if (!process.env.SENTRY_DSN) {
+    throw new Error("SENTRY_DSN environment variable is required");
+  }
   Sentry.init({
     dsn: process.env.SENTRY_DSN,
     environment: process.env.NODE_ENV === "production" ? "production" : "development",
   });
 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
init: async () => {
Sentry.init({
// The Data Source Name (DSN) is a unique identifier for your Sentry project.
dsn: process.env.SENTRY_DSN,
// Update this to match the environment you want to track errors for
environment: process.env.NODE_ENV === "production" ? "production" : "development",
});
},
init: async () => {
if (!process.env.SENTRY_DSN) {
throw new Error("SENTRY_DSN environment variable is required");
}
Sentry.init({
// The Data Source Name (DSN) is a unique identifier for your Sentry project.
dsn: process.env.SENTRY_DSN,
// Update this to match the environment you want to track errors for
environment: process.env.NODE_ENV === "production" ? "production" : "development",
});
},

onFailure: async (payload, error, { ctx }) => {
Sentry.captureException(error, {
extra: {
payload,
ctx,
},
});
},
});
Comment on lines +58 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling in the onFailure handler.

The current implementation might swallow errors. Consider:

  1. Adding error logging
  2. Implementing proper error propagation
 onFailure: async (payload, error, { ctx }) => {
+  console.error("Task failed:", error);
   Sentry.captureException(error, {
     extra: {
       payload,
       ctx,
     },
   });
+  // Re-throw the error to ensure it's properly propagated
+  throw error;
 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onFailure: async (payload, error, { ctx }) => {
Sentry.captureException(error, {
extra: {
payload,
ctx,
},
});
},
});
onFailure: async (payload, error, { ctx }) => {
console.error("Task failed:", error);
Sentry.captureException(error, {
extra: {
payload,
ctx,
},
});
// Re-throw the error to ensure it's properly propagated
throw error;
},
});

```

<Note>
[Build extensions](/config/config-file#extensions) allow you to hook into the build system and
customize the build process or the resulting bundle and container image (in the case of
deploying). You can use pre-built extensions or create your own.
</Note>

## Testing that errors are being sent to Sentry

To test that errors are being sent to Sentry, you need to create a task that will fail.

This task takes no payload, and will throw an error.

```ts trigger/sentry-error-test.ts
import { task } from "@trigger.dev/sdk/v3";

export const sentryErrorTest = task({
id: "sentry-error-test",
retry: {
// Only retry once
maxAttempts: 1,
},
run: async () => {
const error = new Error("This is a custom error that Sentry will capture");
error.cause = { additionalContext: "This is additional context" };
throw error;
},
});
```
Comment on lines +81 to +96
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make the test task more realistic and informative.

The current test task is overly simplistic. Consider:

  1. Adding more realistic error scenarios
  2. Including structured metadata
  3. Using Sentry's breadcrumbs feature
 export const sentryErrorTest = task({
   id: "sentry-error-test",
   retry: {
     maxAttempts: 1,
   },
   run: async () => {
+    // Add breadcrumb for better error context
+    Sentry.addBreadcrumb({
+      category: 'task',
+      message: 'Starting sentry test task',
+      level: 'info',
+    });
+
+    // Simulate a more realistic error scenario
+    try {
+      const result = await simulateApiCall();
+      // Process result...
+    } catch (e) {
       const error = new Error("This is a custom error that Sentry will capture");
-      error.cause = { additionalContext: "This is additional context" };
+      error.cause = {
+        originalError: e,
+        context: {
+          taskId: "sentry-error-test",
+          timestamp: new Date().toISOString(),
+          environment: process.env.NODE_ENV,
+        }
+      };
       throw error;
+    }
   },
 });

Committable suggestion was skipped due to low confidence.


After creating the task, deploy your project.

<CodeGroup>

```bash npm
npx trigger.dev@latest deploy
```

```bash pnpm
pnpm dlx trigger.dev@latest deploy
```

```bash yarn
yarn dlx trigger.dev@latest deploy
```

</CodeGroup>

Once deployed, navigate to the `test` page in the sidebar of your [Trigger.dev dashboard](https://cloud.trigger.dev), click on your `prod` environment, and select the `sentryErrorTest` task.

Run a test task with an empty payload by clicking the `Run test` button.

Your run should then fail, and if everything is set up correctly, you will see an error in the Sentry project dashboard shortly after.
1 change: 1 addition & 0 deletions docs/guides/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Tasks you can copy and paste to get started with Trigger.dev. They can all be ex
| [React to PDF](/guides/examples/react-pdf) | Use `react-pdf` to generate a PDF and save it to Cloudflare R2. |
| [Puppeteer](/guides/examples/puppeteer) | Use Puppeteer to generate a PDF or scrape a webpage. |
| [Resend email sequence](/guides/examples/resend-email-sequence) | Send a sequence of emails over several days using Resend with Trigger.dev. |
| [Sentry error tracking](/guides/examples/sentry-error-tracking) | Automatically send errors to Sentry from your tasks. |
| [Sharp image processing](/guides/examples/sharp-image-processing) | Use Sharp to process an image and save it to Cloudflare R2. |
| [Supabase database operations](/guides/examples/supabase-database-operations) | Run basic CRUD operations on a table in a Supabase database using Trigger.dev. |
| [Supabase Storage upload](/guides/examples/supabase-storage-upload) | Download a video from a URL and upload it to Supabase Storage using S3. |
Expand Down
1 change: 1 addition & 0 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@
"guides/examples/pdf-to-image",
"guides/examples/puppeteer",
"guides/examples/scrape-hacker-news",
"guides/examples/sentry-error-tracking",
"guides/examples/sharp-image-processing",
"guides/examples/supabase-database-operations",
"guides/examples/supabase-storage-upload",
Expand Down