mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-09 20:12:26 +10:00
integrate sentry for error logging
This commit is contained in:
@ -2,6 +2,10 @@
|
||||
TURBO_TEAM=
|
||||
TURBO_TOKEN=
|
||||
|
||||
# Error Logging
|
||||
SERVER_SENTRY_DSN=
|
||||
PUBLIC_CLIENT_SENTRY_DSN=
|
||||
|
||||
# Server + Client
|
||||
TZ=UTC
|
||||
PUBLIC_URL=http://localhost:3000
|
||||
|
||||
1
.github/workflows/docker-build-push.yml
vendored
1
.github/workflows/docker-build-push.yml
vendored
@ -53,6 +53,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: ${{ matrix.arch }}
|
||||
file: ${{ matrix.image }}/Dockerfile
|
||||
tags: |
|
||||
amruthpillai/reactive-resume:${{ matrix.image }}-latest
|
||||
|
||||
5
client/.gitignore
vendored
5
client/.gitignore
vendored
@ -39,4 +39,7 @@ yarn-error.log*
|
||||
__ENV.js
|
||||
|
||||
# next-sitemap
|
||||
sitemap*.xml
|
||||
sitemap*.xml
|
||||
|
||||
# Sentry
|
||||
.sentryclirc
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const { version } = require('../package.json');
|
||||
const { i18n } = require('./next-i18next.config');
|
||||
const { withSentryConfig } = require('@sentry/nextjs');
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
@ -15,6 +16,10 @@ const nextConfig = {
|
||||
domains: ['cdn.rxresu.me', 'www.gravatar.com'],
|
||||
},
|
||||
|
||||
sentry: {
|
||||
hideSourceMaps: true,
|
||||
},
|
||||
|
||||
// Hack to make Tailwind darkMode 'class' strategy with CSS Modules
|
||||
// Ref: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomment-968368156
|
||||
webpack: (config) => {
|
||||
@ -47,4 +52,9 @@ const nextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
/** @type {import('@sentry/nextjs').SentryWebpackPluginOptions} */
|
||||
const sentryConfig = {
|
||||
silent: true,
|
||||
};
|
||||
|
||||
module.exports = withSentryConfig(nextConfig, sentryConfig);
|
||||
|
||||
@ -21,9 +21,10 @@
|
||||
"@mui/material": "^5.10.15",
|
||||
"@mui/system": "^5.10.15",
|
||||
"@mui/x-date-pickers": "5.0.8",
|
||||
"@next/env": "^13.0.4",
|
||||
"@next/env": "^13.0.5",
|
||||
"@react-oauth/google": "^0.5.0",
|
||||
"@reduxjs/toolkit": "^1.9.0",
|
||||
"@sentry/nextjs": "^7.21.1",
|
||||
"axios": "^1.2.0",
|
||||
"clsx": "^1.2.1",
|
||||
"dayjs": "^1.11.6",
|
||||
@ -33,7 +34,7 @@
|
||||
"md5-hex": "^4.0.0",
|
||||
"monaco-editor": "^0.34.1",
|
||||
"nanoid": "^3.3.4",
|
||||
"next": "13.0.4",
|
||||
"next": "13.0.5",
|
||||
"next-i18next": "^13.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-colorful": "^5.6.1",
|
||||
@ -59,10 +60,9 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.2",
|
||||
"@reactive-resume/schema": "workspace:*",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"@tailwindcss/typography": "^0.5.8",
|
||||
"@types/downloadjs": "^1.4.3",
|
||||
"@types/lodash": "^4.14.189",
|
||||
"@types/lodash": "^4.14.190",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/react": "^18.0.25",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
@ -72,8 +72,9 @@
|
||||
"@types/webfontloader": "^1.6.35",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"csstype": "^3.1.1",
|
||||
"eslint-config-next": "^13.0.4",
|
||||
"eslint-config-next": "^13.0.5",
|
||||
"eslint-plugin-tailwindcss": "^3.7.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"next-sitemap": "^3.1.32",
|
||||
"postcss": "^8.4.19",
|
||||
"sass": "^1.56.1",
|
||||
|
||||
16
client/pages/_error.tsx
Normal file
16
client/pages/_error.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
import type { NextPage } from 'next';
|
||||
import type { ErrorProps } from 'next/error';
|
||||
import NextErrorComponent from 'next/error';
|
||||
|
||||
const CustomErrorComponent: NextPage<ErrorProps> = (props) => {
|
||||
return <NextErrorComponent statusCode={props.statusCode} />;
|
||||
};
|
||||
|
||||
CustomErrorComponent.getInitialProps = async (contextData) => {
|
||||
await Sentry.captureUnderscoreErrorException(contextData);
|
||||
|
||||
return NextErrorComponent.getInitialProps(contextData);
|
||||
};
|
||||
|
||||
export default CustomErrorComponent;
|
||||
7
client/sentry.client.config.js
Normal file
7
client/sentry.client.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
import env from '@beam-australia/react-env';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
Sentry.init({
|
||||
dsn: env('CLIENT_SENTRY_DSN'),
|
||||
tracesSampleRate: 1.0,
|
||||
});
|
||||
3
client/sentry.properties
Normal file
3
client/sentry.properties
Normal file
@ -0,0 +1,3 @@
|
||||
defaults.project=client
|
||||
defaults.org=reactive-resume
|
||||
defaults.url=https://sentry.io/
|
||||
7
client/sentry.server.config.js
Normal file
7
client/sentry.server.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
import env from '@beam-australia/react-env';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
Sentry.init({
|
||||
dsn: env('CLIENT_SENTRY_DSN'),
|
||||
tracesSampleRate: 1.0,
|
||||
});
|
||||
@ -19,7 +19,6 @@ const axios = _axios.create({ baseURL });
|
||||
axios.interceptors.request.use((config) => {
|
||||
const { accessToken } = store.getState().auth;
|
||||
|
||||
// @ts-ignore
|
||||
config.headers = {
|
||||
...config.headers,
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
|
||||
792
pnpm-lock.yaml
generated
792
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@
|
||||
"@nestjs/serve-static": "^3.0.0",
|
||||
"@nestjs/terminus": "^9.1.3",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"@sentry/node": "^7.21.1",
|
||||
"@types/passport": "^1.0.11",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cache-manager": "^5.1.3",
|
||||
@ -41,7 +42,7 @@
|
||||
"passport-local": "^1.0.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pg": "^8.8.0",
|
||||
"playwright-chromium": "^1.28.0",
|
||||
"playwright-chromium": "^1.28.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.5.7",
|
||||
@ -55,7 +56,7 @@
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/lodash": "^4.14.189",
|
||||
"@types/lodash": "^4.14.190",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/nodemailer": "^6.4.6",
|
||||
|
||||
3
server/sentry.properties
Normal file
3
server/sentry.properties
Normal file
@ -0,0 +1,3 @@
|
||||
defaults.project=server
|
||||
defaults.org=reactive-resume
|
||||
defaults.url=https://sentry.io/
|
||||
@ -11,6 +11,7 @@ import { HttpExceptionFilter } from './filters/http-exception.filter';
|
||||
import { FontsModule } from './fonts/fonts.module';
|
||||
import { HealthModule } from './health/health.module';
|
||||
import { IntegrationsModule } from './integrations/integrations.module';
|
||||
import { SentryInterceptor } from './interceptors/sentry.interceptor';
|
||||
import { MailModule } from './mail/mail.module';
|
||||
import { PrinterModule } from './printer/printer.module';
|
||||
import { ResumeModule } from './resume/resume.module';
|
||||
@ -40,6 +41,10 @@ import { UsersModule } from './users/users.module';
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: ClassSerializerInterceptor,
|
||||
},
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: SentryInterceptor,
|
||||
},
|
||||
{
|
||||
provide: APP_FILTER,
|
||||
useClass: HttpExceptionFilter,
|
||||
|
||||
@ -7,6 +7,7 @@ import authConfig from './auth.config';
|
||||
import cacheConfig from './cache.config';
|
||||
import databaseConfig from './database.config';
|
||||
import googleConfig from './google.config';
|
||||
import loggingConfig from './logging.config';
|
||||
import mailConfig from './mail.config';
|
||||
import storageConfig from './storage.config';
|
||||
|
||||
@ -58,12 +59,24 @@ const validationSchema = Joi.object({
|
||||
PDF_DELETION_TIME: Joi.number()
|
||||
.default(4 * 24 * 60 * 60 * 1000) // 4 days
|
||||
.allow(''),
|
||||
|
||||
// Logging
|
||||
SERVER_SENTRY_DSN: Joi.string().allow(''),
|
||||
});
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
NestConfigModule.forRoot({
|
||||
load: [appConfig, authConfig, cacheConfig, databaseConfig, googleConfig, mailConfig, storageConfig],
|
||||
load: [
|
||||
appConfig,
|
||||
authConfig,
|
||||
cacheConfig,
|
||||
databaseConfig,
|
||||
googleConfig,
|
||||
mailConfig,
|
||||
storageConfig,
|
||||
loggingConfig,
|
||||
],
|
||||
validationSchema: validationSchema,
|
||||
}),
|
||||
],
|
||||
|
||||
5
server/src/config/logging.config.ts
Normal file
5
server/src/config/logging.config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('logging', () => ({
|
||||
sentryDSN: process.env.SERVER_SENTRY_DSN,
|
||||
}));
|
||||
15
server/src/interceptors/sentry.interceptor.ts
Normal file
15
server/src/interceptors/sentry.interceptor.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class SentryInterceptor implements NestInterceptor {
|
||||
intercept(_context: ExecutionContext, next: CallHandler): Observable<any> {
|
||||
return next.handle().pipe(
|
||||
tap(null, (exception) => {
|
||||
Sentry.captureException(exception);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,14 @@ import { Logger, ValidationPipe } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import cookieParser from 'cookie-parser';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
const bootstrap = async () => {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
const configService = app.get(ConfigService);
|
||||
|
||||
// Middleware
|
||||
app.enableCors({ credentials: true });
|
||||
@ -17,9 +19,11 @@ const bootstrap = async () => {
|
||||
// Pipes
|
||||
app.useGlobalPipes(new ValidationPipe({ transform: true }));
|
||||
|
||||
const configService = app.get(ConfigService);
|
||||
const port = configService.get<number>('app.port');
|
||||
// Error Logging
|
||||
Sentry.init({ dsn: configService.get<string>('logging.sentryDSN') });
|
||||
|
||||
// Server Port
|
||||
const port = configService.get<number>('app.port');
|
||||
await app.listen(port);
|
||||
|
||||
Logger.log(`🚀 Server is up and running!`);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Controller, Get, Param, Query } from '@nestjs/common';
|
||||
import { Controller, Get, InternalServerErrorException, Param, Query } from '@nestjs/common';
|
||||
|
||||
import { PrinterService } from './printer.service';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user