From b137b4aa2519d970893b1cfd2c4f785f0c8b3bc2 Mon Sep 17 00:00:00 2001 From: Steven Eubank Date: Wed, 8 Jan 2025 16:19:04 +0100 Subject: [PATCH 1/7] feat: add sentry recipe Create a Sentry Recipe [referencing](https://github.com/nestjs/docs.nestjs.com/pull/2572/files#diff-108a454d0f02798009b919d09dbc1afdfbeecdd748122f4426a7512b4b8e7488) --- content/recipes/sentry.md | 129 ++++++++++++++++++ src/app/homepage/menu/menu.component.ts | 1 + .../homepage/pages/recipes/recipes.module.ts | 7 + .../pages/recipes/sentry/sentry.component.ts | 9 ++ 4 files changed, 146 insertions(+) create mode 100644 content/recipes/sentry.md create mode 100644 src/app/homepage/pages/recipes/sentry/sentry.component.ts diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md new file mode 100644 index 0000000000..3a6dd1c1c7 --- /dev/null +++ b/content/recipes/sentry.md @@ -0,0 +1,129 @@ +### Sentry + +[Sentry](https://sentry.io) is an error monitoring and performance tracking platform that helps developers identify and fix issues in real-time. This recipe shows how to integrate Sentry with your NestJS application for error monitoring and distributed tracing. + +#### Installation + +First, install the required dependencies: + + +```bash +$ npm install --save @sentry/nestjs @sentry/profiling-node +``` + + +#### Basic Setup + +To get started with Sentry, you'll need to create an initialization file (e.g., `sentry.init.ts`) that should be imported before any other modules in your application: + +```typescript +import as Sentry from '@sentry/nestjs'; +import { nodeProfilingIntegration } from '@sentry/profiling-node'; +Sentry.init({ +dsn: 'your-sentry-dsn', +integrations: [ +nodeProfilingIntegration(), +], +// Set sampling rate for tracing (adjust in production) +tracesSampleRate: 1.0, +// Set sampling rate for profiling +profilesSampleRate: 1.0, +}); + +``` + + +Update your `main.ts` file to import the Sentry initialization before other imports: + + +```typescript +// Import Sentry initialization first +import './sentry.init'; +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; +async function bootstrap() { +const app = await NestFactory.create(AppModule); +await app.listen(3000); +} +bootstrap(); +``` + + +#### Module Integration + +Add the SentryModule to your application's root module: + + +```typescript +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 + +To ensure Sentry captures unhandled exceptions, you can add the SentryGlobalFilter to your application module: + +```typescript +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 {} +``` + + +For custom exception filters, you can use the `@SentryExceptionCaptured()` decorator: + +```typescript +import { Catch, ExceptionFilter } from '@nestjs/common'; +import { SentryExceptionCaptured } from '@sentry/nestjs'; +@Catch() +export class AllExceptionsFilter implements ExceptionFilter { +@SentryExceptionCaptured() +catch(exception: unknown, host: ArgumentsHost) { +// Your exception handling logic +} +} +``` + + +#### Testing the Integration + +To verify your Sentry integration is working, you can add a test endpoint that throws an error: + +```typescript +import { Controller, Get } from '@nestjs/common'; +@Controller() +export class AppController { +@Get('debug-sentry') +testSentry() { +throw new Error('Test Sentry Integration!'); +} +} +``` + + +Visit `/debug-sentry` in your application, and you should see the error appear in your Sentry dashboard. + +> info **Hint** For complete documentation about Sentry's NestJS integration, including advanced configuration options and features, visit the [official Sentry documentation](https://docs.sentry.io/platforms/javascript/guides/nestjs/). + diff --git a/src/app/homepage/menu/menu.component.ts b/src/app/homepage/menu/menu.component.ts index f90fd18b56..b70bbe11fd 100644 --- a/src/app/homepage/menu/menu.component.ts +++ b/src/app/homepage/menu/menu.component.ts @@ -246,6 +246,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 {} From bbc481d965ef899bf6dcae85260244bd5f66a6a4 Mon Sep 17 00:00:00 2001 From: Steven Eubank Date: Wed, 8 Jan 2025 16:42:02 +0100 Subject: [PATCH 2/7] fix: clean up fix some snippets and text, stick with CJS, and link to Sentry to cover ESM related topics --- content/recipes/sentry.md | 123 ++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 64 deletions(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index 3a6dd1c1c7..c1112f8eb7 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -10,6 +10,7 @@ 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 @@ -17,19 +18,28 @@ $ npm install --save @sentry/nestjs @sentry/profiling-node To get started with Sentry, you'll need to create an initialization file (e.g., `sentry.init.ts`) that should be imported before any other modules in your application: ```typescript -import as Sentry from '@sentry/nestjs'; -import { nodeProfilingIntegration } from '@sentry/profiling-node'; +@@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: 'your-sentry-dsn', -integrations: [ -nodeProfilingIntegration(), -], -// Set sampling rate for tracing (adjust in production) -tracesSampleRate: 1.0, -// Set sampling rate for profiling -profilesSampleRate: 1.0, + 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, }); + ``` @@ -37,15 +47,21 @@ Update your `main.ts` file to import the Sentry initialization before other impo ```typescript -// Import Sentry initialization first -import './sentry.init'; -import { NestFactory } from '@nestjs/core'; -import { AppModule } from './app.module'; +@@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); + const app = await NestFactory.create(AppModule); + await app.listen(3000); } + bootstrap(); + ``` @@ -55,55 +71,34 @@ Add the SentryModule to your application's root module: ```typescript -import { Module } from '@nestjs/common'; -import { SentryModule } from '@sentry/nestjs/setup'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; +@@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], + imports: [ + SentryModule.forRoot(), + // ...other modules + ], + controllers: [AppController], + providers: [AppService], }) export class AppModule {} ``` +> info **Hint** *Running with ESM*: If you run your application with ESM, you'll need to import the Sentry Initialization file before importing any other modules. Read about [running Sentry with ESM](https://docs.sentry.io/platforms/javascript/guides/nestjs/install/esm/). If you're not sure about how you're running your application, see [Installation Methods](https://docs.sentry.io/platforms/javascript/guides/nestjs/install/) for more information. -#### Exception Handling - -To ensure Sentry captures unhandled exceptions, you can add the SentryGlobalFilter to your application module: -```typescript -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. -For custom exception filters, you can use the `@SentryExceptionCaptured()` decorator: +To fix this, upload your source maps to Sentry. The easiest way to do this is by using the Sentry Wizard: -```typescript -import { Catch, ExceptionFilter } from '@nestjs/common'; -import { SentryExceptionCaptured } from '@sentry/nestjs'; -@Catch() -export class AllExceptionsFilter implements ExceptionFilter { -@SentryExceptionCaptured() -catch(exception: unknown, host: ArgumentsHost) { -// Your exception handling logic -} -} +```bash +npx @sentry/wizard@latest -i sourcemaps ``` @@ -112,18 +107,18 @@ catch(exception: unknown, host: ArgumentsHost) { To verify your Sentry integration is working, you can add a test endpoint that throws an error: ```typescript -import { Controller, Get } from '@nestjs/common'; -@Controller() -export class AppController { -@Get('debug-sentry') -testSentry() { -throw new Error('Test Sentry Integration!'); +@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. -> info **Hint** For complete documentation about Sentry's NestJS integration, including advanced configuration options and features, visit the [official Sentry documentation](https://docs.sentry.io/platforms/javascript/guides/nestjs/). +### 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). \ No newline at end of file From fb539f9c2d99aa5b9f287f691b2108e1eb79bd66 Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:06:27 +0100 Subject: [PATCH 3/7] Update sentry.md --- content/recipes/sentry.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index c1112f8eb7..4354c8c67d 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -1,6 +1,6 @@ ### Sentry -[Sentry](https://sentry.io) is an error monitoring and performance tracking platform that helps developers identify and fix issues in real-time. This recipe shows how to integrate Sentry with your NestJS application for error monitoring and distributed tracing. +[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 with your NestJS application. #### Installation @@ -15,7 +15,7 @@ $ npm install --save @sentry/nestjs @sentry/profiling-node #### Basic Setup -To get started with Sentry, you'll need to create an initialization file (e.g., `sentry.init.ts`) that should be imported before any other modules in your application: +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) @@ -43,7 +43,7 @@ Sentry.init({ ``` -Update your `main.ts` file to import the Sentry initialization before other imports: +Update your `main.ts` file to import `instrume.js` before other imports: ```typescript @@ -64,10 +64,7 @@ bootstrap(); ``` - -#### Module Integration - -Add the SentryModule to your application's root module: +Afterward, add the `SentryModule` as a root module to your main module: ```typescript @@ -121,4 +118,4 @@ Visit `/debug-sentry` in your application, and you should see the error appear i 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). \ No newline at end of file +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). From 9f9991d034673c027375b4c9ecc57d3b3f152b98 Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:33:31 +0100 Subject: [PATCH 4/7] Update content/recipes/sentry.md Co-authored-by: Charly Gomez --- content/recipes/sentry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index 4354c8c67d..da9cfa01de 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -43,7 +43,7 @@ Sentry.init({ ``` -Update your `main.ts` file to import `instrume.js` before other imports: +Update your `main.ts` file to import `instrument.js` before other imports: ```typescript From b3dc1a4f0606353b7951ffa4222d973e875c1f8b Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Thu, 9 Jan 2025 21:34:43 +0100 Subject: [PATCH 5/7] removing based review ESM information is in Sentry docs, should someone need it. --- content/recipes/sentry.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index da9cfa01de..5bb0397eea 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -85,9 +85,6 @@ import { AppService } from "./app.service"; export class AppModule {} ``` -> info **Hint** *Running with ESM*: If you run your application with ESM, you'll need to import the Sentry Initialization file before importing any other modules. Read about [running Sentry with ESM](https://docs.sentry.io/platforms/javascript/guides/nestjs/install/esm/). If you're not sure about how you're running your application, see [Installation Methods](https://docs.sentry.io/platforms/javascript/guides/nestjs/install/) for more information. - - #### 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. From 833a5a28ad9eb7e4fc6fd140b76f3f935bba08b1 Mon Sep 17 00:00:00 2001 From: Steven Eubank Date: Thu, 9 Jan 2025 21:59:16 +0100 Subject: [PATCH 6/7] fix: excepting snippets --- content/recipes/sentry.md | 45 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index 5bb0397eea..da6cf6bbec 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -1,6 +1,6 @@ ### 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 with your NestJS application. +[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 @@ -67,7 +67,7 @@ bootstrap(); Afterward, add the `SentryModule` as a root module to your main module: -```typescript +```typescript {2, 8} @@filename(app.module) import { Module } from "@nestjs/common"; import { SentryModule } from "@sentry/nestjs/setup"; @@ -85,6 +85,47 @@ import { AppService } from "./app.service"; 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. From 5df63d5445c7731d985353ba93d53716045ee285 Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Sat, 11 Jan 2025 18:35:25 +0100 Subject: [PATCH 7/7] Update content/recipes/sentry.md Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> --- content/recipes/sentry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/recipes/sentry.md b/content/recipes/sentry.md index da6cf6bbec..54e296d406 100644 --- a/content/recipes/sentry.md +++ b/content/recipes/sentry.md @@ -64,7 +64,7 @@ bootstrap(); ``` -Afterward, add the `SentryModule` as a root module to your main module: +Afterwards, add the `SentryModule` as a root module to your main module: ```typescript {2, 8}