Skip to content

Commit a74cc99

Browse files
Merge branch 'sentry-recipe' of https://github.com/smeubank/docs.nestjs.com into smeubank-sentry-recipe
2 parents 8963547 + b38a6dc commit a74cc99

File tree

4 files changed

+176
-0
lines changed

4 files changed

+176
-0
lines changed

content/recipes/sentry.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
### Sentry
2+
3+
[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.
4+
5+
#### Installation
6+
7+
First, install the required dependencies:
8+
9+
10+
```bash
11+
$ npm install --save @sentry/nestjs @sentry/profiling-node
12+
```
13+
> info **Hint** we support `yarn` and `pnpm` as well. @sentry/profiling-node is optional, but recommended for performance profiling.
14+
15+
16+
#### Basic Setup
17+
18+
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:
19+
20+
```typescript
21+
@@filename(instrument)
22+
const Sentry = require("@sentry/nestjs");
23+
const { nodeProfilingIntegration } = require("@sentry/profiling-node");
24+
25+
// Ensure to call this before requiring any other modules!
26+
Sentry.init({
27+
dsn: SENTRY_DSN,
28+
integrations: [
29+
// Add our Profiling integration
30+
nodeProfilingIntegration(),
31+
],
32+
33+
// Add Tracing by setting tracesSampleRate
34+
// We recommend adjusting this value in production
35+
tracesSampleRate: 1.0,
36+
37+
// Set sampling rate for profiling
38+
// This is relative to tracesSampleRate
39+
profilesSampleRate: 1.0,
40+
});
41+
42+
43+
```
44+
45+
46+
Update your `main.ts` file to import `instrument.js` before other imports:
47+
48+
49+
```typescript
50+
@@filename(main)
51+
// Import this first!
52+
import "./instrument";
53+
54+
// Now import other modules
55+
import { NestFactory } from "@nestjs/core";
56+
import { AppModule } from "./app.module";
57+
58+
async function bootstrap() {
59+
const app = await NestFactory.create(AppModule);
60+
await app.listen(3000);
61+
}
62+
63+
bootstrap();
64+
65+
```
66+
67+
Afterwards, add the `SentryModule` as a root module to your main module:
68+
69+
70+
```typescript {2, 8}
71+
@@filename(app.module)
72+
import { Module } from "@nestjs/common";
73+
import { SentryModule } from "@sentry/nestjs/setup";
74+
import { AppController } from "./app.controller";
75+
import { AppService } from "./app.service";
76+
77+
@Module({
78+
imports: [
79+
SentryModule.forRoot(),
80+
// ...other modules
81+
],
82+
controllers: [AppController],
83+
providers: [AppService],
84+
})
85+
export class AppModule {}
86+
```
87+
88+
#### Exception Handling
89+
90+
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:
91+
92+
```typescript {2, 6}
93+
import { Catch, ExceptionFilter } from '@nestjs/common';
94+
import { SentryExceptionCaptured } from '@sentry/nestjs';
95+
96+
@Catch()
97+
export class YourCatchAllExceptionFilter implements ExceptionFilter {
98+
@SentryExceptionCaptured()
99+
catch(exception, host): void {
100+
// your implementation here
101+
}
102+
}
103+
```
104+
105+
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.
106+
107+
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.
108+
109+
> warning **Important** The `SentryGlobalFilter` needs to be registered before any other exception filters.
110+
111+
```typescript {3, 9}
112+
@@filename(app.module)
113+
import { Module } from "@nestjs/common";
114+
import { APP_FILTER } from "@nestjs/core";
115+
+import { SentryGlobalFilter } from "@sentry/nestjs/setup";
116+
117+
@Module({
118+
providers: [
119+
{
120+
provide: APP_FILTER,
121+
useClass: SentryGlobalFilter,
122+
},
123+
// ..other providers
124+
],
125+
})
126+
export class AppModule {}
127+
```
128+
129+
#### Add Readable Stack Traces to Errors
130+
131+
Depending on how you've set up your project, the stack traces in your Sentry errors probably won't look like your actual code.
132+
133+
To fix this, upload your source maps to Sentry. The easiest way to do this is by using the Sentry Wizard:
134+
135+
```bash
136+
npx @sentry/wizard@latest -i sourcemaps
137+
```
138+
139+
140+
#### Testing the Integration
141+
142+
To verify your Sentry integration is working, you can add a test endpoint that throws an error:
143+
144+
```typescript
145+
@Get("/debug-sentry")
146+
getError() {
147+
throw new Error("My first Sentry error!");
148+
}
149+
150+
```
151+
152+
Visit `/debug-sentry` in your application, and you should see the error appear in your Sentry dashboard.
153+
154+
155+
### Summary
156+
157+
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/).
158+
159+
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).

src/app/homepage/menu/menu.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export class MenuComponent implements OnInit {
244244
{ title: 'CQRS', path: '/recipes/cqrs' },
245245
{ title: 'Compodoc', path: '/recipes/documentation' },
246246
{ title: 'Prisma', path: '/recipes/prisma' },
247+
{ title: 'Sentry', path: '/recipes/sentry' },
247248
{ title: 'Serve static', path: '/recipes/serve-static' },
248249
{ title: 'Commander', path: '/recipes/nest-commander' },
249250
{ title: 'Async local storage', path: '/recipes/async-local-storage' },

src/app/homepage/pages/recipes/recipes.module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { MikroOrmComponent } from './mikroorm/mikroorm.component';
1010
import { MongodbComponent } from './mongodb/mongodb.component';
1111
import { PrismaComponent } from './prisma/prisma.component';
1212
import { ReplComponent } from './repl/repl.component';
13+
import { SentryComponent } from './sentry/sentry.component';
1314
import { ServeStaticComponent } from './serve-static/serve-static.component';
1415
import { SqlSequelizeComponent } from './sql-sequelize/sql-sequelize.component';
1516
import { SqlTypeormComponent } from './sql-typeorm/sql-typeorm.component';
@@ -48,6 +49,11 @@ const routes: Routes = [
4849
component: CqrsComponent,
4950
data: { title: 'CQRS' },
5051
},
52+
{
53+
path: 'sentry',
54+
component: SentryComponent,
55+
data: { title: 'Sentry' },
56+
},
5157
{
5258
path: 'swagger',
5359
redirectTo: '/openapi/introduction',
@@ -142,6 +148,7 @@ const routes: Routes = [
142148
MikroOrmComponent,
143149
SqlTypeormComponent,
144150
SqlSequelizeComponent,
151+
SentryComponent,
145152
MongodbComponent,
146153
PrismaComponent,
147154
CqrsComponent,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { BasePageComponent } from '../../page/page.component';
3+
4+
@Component({
5+
selector: 'app-sentry',
6+
templateUrl: './sentry.component.html',
7+
changeDetection: ChangeDetectionStrategy.OnPush,
8+
})
9+
export class SentryComponent extends BasePageComponent {}

0 commit comments

Comments
 (0)