Skip to content

Commit

Permalink
feat(nestjs): Add alias @SentryExceptionCaptured for @WithSentry (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst authored Nov 18, 2024
1 parent 43c7079 commit 538702e
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common';
import { WithSentry } from '@sentry/nestjs';
import { SentryExceptionCaptured } from '@sentry/nestjs';
import { Request, Response } from 'express';

@Catch()
export class ExampleWrappedGlobalFilter implements ExceptionFilter {
@WithSentry()
@SentryExceptionCaptured()
catch(exception: BadRequestException, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
Expand Down
6 changes: 3 additions & 3 deletions packages/nestjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,16 @@ export class AppModule {}

In case you are 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 an empty `@Catch()`
decorator), add a `@WithSentry()` decorator to the `catch()` method of this global error filter. This decorator will
report all unexpected errors that are received by your global error filter to Sentry:
decorator), add a `@SentryExceptionCaptured()` decorator to the `catch()` method of this global error filter. This
decorator will report all unexpected errors that are received by your global error filter to Sentry:

```typescript
import { Catch, ExceptionFilter } from '@nestjs/common';
import { WithSentry } from '@sentry/nestjs';

@Catch()
export class YourCatchAllExceptionFilter implements ExceptionFilter {
@WithSentry()
@SentryExceptionCaptured()
catch(exception, host): void {
// your implementation here
}
Expand Down
87 changes: 87 additions & 0 deletions packages/nestjs/src/decorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { captureException } from '@sentry/core';
import * as Sentry from '@sentry/node';
import { startSpan } from '@sentry/node';
import type { MonitorConfig } from '@sentry/types';
import { isExpectedError } from './helpers';

/**
* A decorator wrapping the native nest Cron decorator, sending check-ins to Sentry.
*/
export const SentryCron = (monitorSlug: string, monitorConfig?: MonitorConfig): MethodDecorator => {
return (target: unknown, propertyKey, descriptor: PropertyDescriptor) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const originalMethod = descriptor.value as (...args: any[]) => Promise<any>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
descriptor.value = function (...args: any[]) {
return Sentry.withMonitor(
monitorSlug,
() => {
return originalMethod.apply(this, args);
},
monitorConfig,
);
};
return descriptor;
};
};

/**
* A decorator usable to wrap arbitrary functions with spans.
*/
export function SentryTraced(op: string = 'function') {
return function (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const originalMethod = descriptor.value as (...args: any[]) => Promise<any> | any; // function can be sync or async

// eslint-disable-next-line @typescript-eslint/no-explicit-any
descriptor.value = function (...args: any[]) {
return startSpan(
{
op: op,
name: propertyKey,
},
() => {
return originalMethod.apply(this, args);
},
);
};

// preserve the original name on the decorated function
Object.defineProperty(descriptor.value, 'name', {
value: originalMethod.name,
configurable: true,
enumerable: true,
writable: true,
});

return descriptor;
};
}

/**
* A decorator to wrap user-defined exception filters and add Sentry error reporting.
*/
export function SentryExceptionCaptured() {
return function (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const originalCatch = descriptor.value as (exception: unknown, host: unknown, ...args: any[]) => void;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
descriptor.value = function (exception: unknown, host: unknown, ...args: any[]) {
if (isExpectedError(exception)) {
return originalCatch.apply(this, [exception, host, ...args]);
}

captureException(exception);
return originalCatch.apply(this, [exception, host, ...args]);
};

return descriptor;
};
}

/**
* A decorator to wrap user-defined exception filters and add Sentry error reporting.
*/
export const WithSentry = SentryExceptionCaptured;
24 changes: 0 additions & 24 deletions packages/nestjs/src/decorators/sentry-cron.ts

This file was deleted.

34 changes: 0 additions & 34 deletions packages/nestjs/src/decorators/sentry-traced.ts

This file was deleted.

24 changes: 0 additions & 24 deletions packages/nestjs/src/decorators/with-sentry.ts

This file was deleted.

9 changes: 6 additions & 3 deletions packages/nestjs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ export * from '@sentry/node';

export { init } from './sdk';

export { SentryTraced } from './decorators/sentry-traced';
export { SentryCron } from './decorators/sentry-cron';
export { WithSentry } from './decorators/with-sentry';
export {
SentryTraced,
SentryCron,
WithSentry,
SentryExceptionCaptured,
} from './decorators';

0 comments on commit 538702e

Please sign in to comment.