Skip to content
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

feat: add sentry recipe #3175

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
159 changes: 159 additions & 0 deletions content/recipes/sentry.md
Original file line number Diff line number Diff line change
@@ -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).
1 change: 1 addition & 0 deletions src/app/homepage/menu/menu.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
7 changes: 7 additions & 0 deletions src/app/homepage/pages/recipes/recipes.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -48,6 +49,11 @@ const routes: Routes = [
component: CqrsComponent,
data: { title: 'CQRS' },
},
{
path: 'sentry',
component: SentryComponent,
data: { title: 'Sentry' },
},
{
path: 'swagger',
redirectTo: '/openapi/introduction',
Expand Down Expand Up @@ -142,6 +148,7 @@ const routes: Routes = [
MikroOrmComponent,
SqlTypeormComponent,
SqlSequelizeComponent,
SentryComponent,
MongodbComponent,
PrismaComponent,
CqrsComponent,
Expand Down
9 changes: 9 additions & 0 deletions src/app/homepage/pages/recipes/sentry/sentry.component.ts
Original file line number Diff line number Diff line change
@@ -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 {}