diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md new file mode 100644 index 0000000000..54e296d406 --- /dev/null +++ b/content/recipes/sentry.md @@ -0,0 +1,159 @@ +### Sentry + +[Sentry](https://sentry.io) is an error tracking and performance monitoring platform that helps developers identify and fix issues in real-time. This recipe shows how to integrate Sentry's [NestJS SDK](https://docs.sentry.io/platforms/javascript/guides/nestjs/) with your NestJS application. + +#### Installation + +First, install the required dependencies: + + +```bash +$ npm install --save @sentry/nestjs @sentry/profiling-node +``` +> info **Hint** we support `yarn` and `pnpm` as well. @sentry/profiling-node is optional, but recommended for performance profiling. + + +#### Basic Setup + +To get started with Sentry, you'll need to create a file named `instrument.js` that should be imported before any other modules in your application: + +```typescript +@@filename(instrument) +const Sentry = require("@sentry/nestjs"); +const { nodeProfilingIntegration } = require("@sentry/profiling-node"); + +// Ensure to call this before requiring any other modules! +Sentry.init({ + dsn: SENTRY_DSN, + integrations: [ + // Add our Profiling integration + nodeProfilingIntegration(), + ], + + // Add Tracing by setting tracesSampleRate + // We recommend adjusting this value in production + tracesSampleRate: 1.0, + + // Set sampling rate for profiling + // This is relative to tracesSampleRate + profilesSampleRate: 1.0, +}); + + +``` + + +Update your `main.ts` file to import `instrument.js` before other imports: + + +```typescript +@@filename(main) +// Import this first! +import "./instrument"; + +// Now import other modules +import { NestFactory } from "@nestjs/core"; +import { AppModule } from "./app.module"; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + await app.listen(3000); +} + +bootstrap(); + +``` + +Afterwards, add the `SentryModule` as a root module to your main module: + + +```typescript {2, 8} +@@filename(app.module) +import { Module } from "@nestjs/common"; +import { SentryModule } from "@sentry/nestjs/setup"; +import { AppController } from "./app.controller"; +import { AppService } from "./app.service"; + +@Module({ + imports: [ + SentryModule.forRoot(), + // ...other modules + ], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} +``` + +#### Exception Handling + +If you're using a global catch-all exception filter (which is either a filter registered with `app.useGlobalFilters()` or a filter registered in your app module providers annotated with a `@Catch()` decorator without arguments), add a `@SentryExceptionCaptured()` decorator to the filter's `catch()` method. This decorator will report all unexpected errors that are received by your global error filter to Sentry: + +```typescript {2, 6} +import { Catch, ExceptionFilter } from '@nestjs/common'; +import { SentryExceptionCaptured } from '@sentry/nestjs'; + +@Catch() +export class YourCatchAllExceptionFilter implements ExceptionFilter { + @SentryExceptionCaptured() + catch(exception, host): void { + // your implementation here + } +} +``` + +By default, only unhandled exceptions that are not caught by an error filter are reported to Sentry. `HttpExceptions` (including [derivatives](https://docs.nestjs.com/exception-filters#built-in-http-exceptions)) are also not captured by default because they mostly act as control flow vehicles. + +If you don't have a global catch-all exception filter, add the `SentryGlobalFilter` to the providers of your main module. This filter will report any unhandled errors that aren't caught by other error filters to Sentry. + +> warning **Important** The `SentryGlobalFilter` needs to be registered before any other exception filters. + +```typescript {3, 9} +@@filename(app.module) +import { Module } from "@nestjs/common"; +import { APP_FILTER } from "@nestjs/core"; ++import { SentryGlobalFilter } from "@sentry/nestjs/setup"; + +@Module({ + providers: [ + { + provide: APP_FILTER, + useClass: SentryGlobalFilter, + }, + // ..other providers + ], +}) +export class AppModule {} +``` + +#### Add Readable Stack Traces to Errors + +Depending on how you've set up your project, the stack traces in your Sentry errors probably won't look like your actual code. + +To fix this, upload your source maps to Sentry. The easiest way to do this is by using the Sentry Wizard: + +```bash +npx @sentry/wizard@latest -i sourcemaps +``` + + +#### Testing the Integration + +To verify your Sentry integration is working, you can add a test endpoint that throws an error: + +```typescript +@Get("/debug-sentry") +getError() { + throw new Error("My first Sentry error!"); +} + +``` + +Visit `/debug-sentry` in your application, and you should see the error appear in your Sentry dashboard. + + +### Summary + +For complete documentation about Sentry's NestJS SDK, including advanced configuration options and features, visit the [official Sentry documentation](https://docs.sentry.io/platforms/javascript/guides/nestjs/). + +While software bugs are Sentry's thing, we still write them. If you come across any problems while installing our SDK, please open a [GitHub Issue](https://github.com/getsentry/sentry-javascript/issues) or reach out on [Discord](https://discord.com/invite/sentry). diff --git a/src/app/homepage/menu/menu.component.ts b/src/app/homepage/menu/menu.component.ts index 817d62227e..6ad9995d1b 100644 --- a/src/app/homepage/menu/menu.component.ts +++ b/src/app/homepage/menu/menu.component.ts @@ -244,6 +244,7 @@ export class MenuComponent implements OnInit { { title: 'CQRS', path: '/recipes/cqrs' }, { title: 'Compodoc', path: '/recipes/documentation' }, { title: 'Prisma', path: '/recipes/prisma' }, + { title: 'Sentry', path: '/recipes/sentry' }, { title: 'Serve static', path: '/recipes/serve-static' }, { title: 'Commander', path: '/recipes/nest-commander' }, { title: 'Async local storage', path: '/recipes/async-local-storage' }, diff --git a/src/app/homepage/pages/recipes/recipes.module.ts b/src/app/homepage/pages/recipes/recipes.module.ts index 6a3da58aab..063117e4d5 100644 --- a/src/app/homepage/pages/recipes/recipes.module.ts +++ b/src/app/homepage/pages/recipes/recipes.module.ts @@ -10,6 +10,7 @@ import { MikroOrmComponent } from './mikroorm/mikroorm.component'; import { MongodbComponent } from './mongodb/mongodb.component'; import { PrismaComponent } from './prisma/prisma.component'; import { ReplComponent } from './repl/repl.component'; +import { SentryComponent } from './sentry/sentry.component'; import { ServeStaticComponent } from './serve-static/serve-static.component'; import { SqlSequelizeComponent } from './sql-sequelize/sql-sequelize.component'; import { SqlTypeormComponent } from './sql-typeorm/sql-typeorm.component'; @@ -48,6 +49,11 @@ const routes: Routes = [ component: CqrsComponent, data: { title: 'CQRS' }, }, + { + path: 'sentry', + component: SentryComponent, + data: { title: 'Sentry' }, + }, { path: 'swagger', redirectTo: '/openapi/introduction', @@ -142,6 +148,7 @@ const routes: Routes = [ MikroOrmComponent, SqlTypeormComponent, SqlSequelizeComponent, + SentryComponent, MongodbComponent, PrismaComponent, CqrsComponent, diff --git a/src/app/homepage/pages/recipes/sentry/sentry.component.ts b/src/app/homepage/pages/recipes/sentry/sentry.component.ts new file mode 100644 index 0000000000..e655391c99 --- /dev/null +++ b/src/app/homepage/pages/recipes/sentry/sentry.component.ts @@ -0,0 +1,9 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { BasePageComponent } from '../../page/page.component'; + +@Component({ + selector: 'app-sentry', + templateUrl: './sentry.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SentryComponent extends BasePageComponent {}