-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Sentry module to simplify integration with Sentry (#2334)
--------- Co-authored-by: Thomas Dax <[email protected]>
- Loading branch information
1 parent
6be41b6
commit 19d53c4
Showing
13 changed files
with
278 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
--- | ||
"@comet/cms-api": minor | ||
--- | ||
|
||
Add Sentry module to simplify integration with Sentry. | ||
|
||
### Usage: | ||
|
||
```ts | ||
// main.ts | ||
|
||
app.use(Sentry.Handlers.requestHandler()); | ||
app.use(Sentry.Handlers.tracingHandler()); | ||
app.use(Sentry.Handlers.errorHandler()); | ||
``` | ||
|
||
```ts | ||
// app.module.ts | ||
|
||
SentryModule.forRootAsync({ | ||
dsn: "sentry_dsn_url", | ||
environment: "dev", | ||
shouldReportException: (exception) => { | ||
// Custom logic to determine if the exception should be reported | ||
return true; | ||
}, | ||
}), | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
title: Sentry Module | ||
sidebar_position: 16 | ||
--- | ||
|
||
SentryModule is a NestJS module that integrates Sentry for error tracking. To use the module, import it into your application's root module and call the `forRootAsync` method. For more detailed configurations and advanced usage please visit [Sentry](https://docs.sentry.io/platforms/javascript/guides/node/configuration/). | ||
|
||
```ts | ||
// app.module.ts | ||
@Module({ | ||
imports: [ | ||
SentryModule.forRootAsync({ | ||
dsn: "sentry_dsn_url", | ||
environment: "dev", | ||
shouldReportException: (exception) => { | ||
// Custom logic to determine if the exception should be reported | ||
return true; | ||
}, | ||
}), | ||
], | ||
}) | ||
export class AppModule {} | ||
``` | ||
|
||
In your main file, add Sentry handlers to capture requests and errors: | ||
|
||
```diff | ||
// main.ts | ||
import { NestFactory } from "@nestjs/core"; | ||
import { NestExpressApplication } from "@nestjs/platform-express"; | ||
+ import * as Sentry from "@sentry/node"; | ||
import { AppModule } from "@src/app.module"; | ||
import { createConfig } from "@src/config/config"; | ||
|
||
async function bootstrap() { | ||
const config = createConfig(process.env); | ||
const appModule = AppModule.forRoot(config); | ||
const app = await NestFactory.create<NestExpressApplication>(appModule); | ||
|
||
+ app.use(Sentry.Handlers.requestHandler()); | ||
+ app.use(Sentry.Handlers.tracingHandler()); | ||
+ app.use(Sentry.Handlers.errorHandler()); | ||
|
||
await app.listen(3000); | ||
} | ||
bootstrap(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const SENTRY_CONFIG = "sentry-config"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor, Optional } from "@nestjs/common"; | ||
import { GqlContextType, GqlExecutionContext } from "@nestjs/graphql"; | ||
import { Observable, tap } from "rxjs"; | ||
|
||
import { SENTRY_CONFIG } from "./sentry.constants"; | ||
import { SentryConfig } from "./sentry.module"; | ||
|
||
@Injectable() | ||
export class SentryInterceptor implements NestInterceptor { | ||
constructor(@Optional() @Inject(SENTRY_CONFIG) private readonly config?: SentryConfig) {} | ||
|
||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> { | ||
return next.handle().pipe( | ||
tap({ | ||
error: async (error) => { | ||
const shouldReport = this.config?.shouldReportException?.(error) ?? true; | ||
|
||
if (shouldReport) { | ||
const Sentry = await import("@sentry/node"); | ||
|
||
await this.configureSentryScopeBasedOnContext(context); | ||
|
||
Sentry.captureException(error); | ||
} | ||
}, | ||
}), | ||
); | ||
} | ||
|
||
private async configureSentryScopeBasedOnContext(context: ExecutionContext) { | ||
const Sentry = await import("@sentry/node"); | ||
|
||
const type = context.getType<GqlContextType>(); | ||
const scope = Sentry.getCurrentScope(); | ||
|
||
if (type === "http") { | ||
const request = context.switchToHttp().getRequest(); | ||
|
||
if (request.user) { | ||
scope.setExtra("user", request.user); | ||
} | ||
|
||
scope.setExtra("method", request.method); | ||
scope.setExtra("url", request.url); | ||
scope.setExtra("body", request.body); | ||
scope.setExtra("query", request.query); | ||
scope.setExtra("params", request.params); | ||
scope.setExtra("headers", request.headers); | ||
} else if (type === "graphql") { | ||
const gqlContext = GqlExecutionContext.create(context); | ||
const request = gqlContext.getContext().req; | ||
|
||
if (request.user) { | ||
scope.setExtra("user", request.user); | ||
} | ||
|
||
scope.setExtra("args", gqlContext.getArgs()); | ||
scope.setExtra("root", gqlContext.getRoot()); | ||
scope.setExtra("context", gqlContext.getContext()); | ||
scope.setExtra("info", gqlContext.getInfo()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { DynamicModule, Module } from "@nestjs/common"; | ||
import { APP_INTERCEPTOR } from "@nestjs/core"; | ||
import type { NodeOptions } from "@sentry/node"; | ||
|
||
import { SENTRY_CONFIG } from "./sentry.constants"; | ||
import { SentryInterceptor } from "./sentry.interceptor"; | ||
|
||
type SentryNodeOptions = Omit<NodeOptions, "dsn" | "environment"> & { | ||
dsn: string; | ||
environment: string; | ||
}; | ||
|
||
type Options = SentryNodeOptions & SentryConfig; | ||
|
||
export type SentryConfig = { | ||
shouldReportException?: (exception: unknown) => boolean; | ||
}; | ||
|
||
@Module({ | ||
providers: [ | ||
{ | ||
provide: APP_INTERCEPTOR, | ||
useClass: SentryInterceptor, | ||
}, | ||
], | ||
}) | ||
export class SentryModule { | ||
static async forRootAsync({ shouldReportException, ...options }: Options): Promise<DynamicModule> { | ||
const Sentry = await import("@sentry/node"); | ||
|
||
const integrations = options.integrations ?? [new Sentry.Integrations.Http({ tracing: true })]; | ||
|
||
Sentry.init({ | ||
...options, | ||
integrations, | ||
}); | ||
|
||
return { | ||
module: SentryModule, | ||
providers: [ | ||
{ | ||
provide: SENTRY_CONFIG, | ||
useValue: { shouldReportException }, | ||
}, | ||
], | ||
}; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.