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: sentry integration #470

Merged
merged 13 commits into from
Dec 11, 2024
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
MODE=dev

#Sentry
SENTRY_ENV=production
SENTRY_DSN=https://fakePublicKey@fake.ingest.sentry.io/123456
SENTRY_ENABLED=false

# URL of RPC node
WEB3=http://localhost:8545
UI_BASE_URL=http://localhost:4200
Expand Down
10 changes: 6 additions & 4 deletions apps/drec-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
"@nestjs/schedule": "1.0.1",
"@nestjs/swagger": "5.2.1",
"@nestjs/typeorm": "8.0.2",
"@sentry/nestjs": "^8.42.0",
"@sentry/node": "^8.42.0",
"ansi-regex": "^4.1.1",
"aws-sdk": "^2.1272.0",
"axios": "0.28.0",
Expand All @@ -85,6 +87,7 @@
"dotenv": "8.2.0",
"ejs": "^3.1.7",
"ethers": "5.3.1",
"express": "4.19.2",
"follow-redirects": "1.15.6",
"form-data": "~4.0.0",
"handlebars": "^4.7.7",
Expand Down Expand Up @@ -114,15 +117,14 @@
"rxjs": "^7.1.0",
"shell-quote": "^1.7.3",
"simple-get": "^2.8.2",
"sql-parser": "~0.5.0",
"stream": "^0.0.2",
"swagger-ui-express": "4.1.6",
"terser": "^5.14.2",
"typeorm": "0.2.41",
"uglify-js": "2.6.0",
"underscore": "^1.12.1",
"uuid": "8.3.2",
"sql-parser": "~0.5.0",
"express": "4.19.2"
"uuid": "8.3.2"
},
"devDependencies": {
"@compodoc/compodoc": "^1.1.22",
Expand All @@ -138,7 +140,7 @@
"@types/luxon": "1.26.5",
"@types/mocha": "8.2.0",
"@types/multer": "1.4.6",
"@types/node": "^14.14.11",
"@types/node": "^14.18.63",
"@types/nodemailer": "^6.4.2",
"@types/passport-jwt": "3.0.3",
"@types/passport-local": "1.0.33",
Expand Down
3,358 changes: 1,540 additions & 1,818 deletions apps/drec-api/pnpm-lock.yaml

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion apps/drec-api/src/drec.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ import { UserLoginSessionEntity } from './pods/user/user_login_session.entity';
import { DeviceLateongoingIssueCertificateEntity } from './pods/device/device_lateongoing_certificate.entity';
import { CertificateSettingEntity } from './pods/device-group/certificate_setting.entity';
import { HttpModule } from '@nestjs/axios';
import { SentryModule } from '@sentry/nestjs/setup';
import { APP_FILTER } from '@nestjs/core';
import { SentryFilter } from './filters/sentry.filter';

const getEnvFilePath = () => {
const pathsToTest = [
Expand Down Expand Up @@ -152,6 +155,7 @@ const QueueingModule = () => {

@Module({
imports: [
SentryModule.forRoot(),
HttpModule,
ConfigModule.forRoot({
envFilePath: getEnvFilePath(),
Expand Down Expand Up @@ -182,6 +186,12 @@ const QueueingModule = () => {
OnChainCertificateModule,
BlockchainPropertiesModule,
],
providers: [OnApplicationBootstrapHookService],
providers: [
OnApplicationBootstrapHookService,
{
provide: APP_FILTER,
useClass: SentryFilter,
},
],
})
export class DrecModule {}
50 changes: 50 additions & 0 deletions apps/drec-api/src/filters/global.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
Logger,
} from '@nestjs/common';
import { WithSentry } from '@sentry/nestjs';
import { ArgumentsHost } from '@nestjs/common';

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
private readonly logger = new Logger(GlobalExceptionFilter.name);

@WithSentry()
catch(exception: Error | HttpException, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();

const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;

let errorResponse: any;

if (exception instanceof HttpException) {
errorResponse = exception.getResponse();
} else {
errorResponse = {
statusCode: status,
message: exception.message || 'Internal server error',
};
}

// Log the error
this.logger.error({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
error: errorResponse,
stack: exception.stack,
environment: process.env.NODE_ENV,
});

// Send the response
response.status(status).json(errorResponse);
}
}
40 changes: 40 additions & 0 deletions apps/drec-api/src/filters/sentry.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { Response } from 'express';
import * as Sentry from '@sentry/node';

@Catch()
export class SentryFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost): void {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();

Sentry.captureException(exception);

const status =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;

let errorResponse: any;

if (exception instanceof HttpException) {
errorResponse = exception.getResponse();
} else {
errorResponse = {
statusCode: status,
message:
exception instanceof Error
? exception.message
: 'Internal server error',
};
}

response.status(status).json(errorResponse);
}
}
2 changes: 1 addition & 1 deletion apps/drec-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { useContainer } from 'class-validator';
import fs from 'fs';
import { DrecModule } from './drec.module';

import './sentry';
import * as PortUtils from './port';

export { DrecModule };
Expand Down
10 changes: 10 additions & 0 deletions apps/drec-api/src/sentry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as Sentry from '@sentry/nestjs';

const { SENTRY_DSN, SENTRY_ENV, SENTRY_ENABLED } = process.env;

Sentry.init({
dsn: SENTRY_DSN,
environment: SENTRY_ENV || 'development',
tracesSampleRate: 1.0,
enabled: SENTRY_DSN && SENTRY_ENABLED?.toLowerCase() === 'true',
});
Loading
Loading