Skip to content

Commit 14e4191

Browse files
Merge branch 'smeubank-sentry-recipe'
2 parents 8963547 + 34a3e8f commit 14e4191

File tree

4 files changed

+166
-0
lines changed

4 files changed

+166
-0
lines changed

content/recipes/sentry.md

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

+1
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

+7
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,
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)