Skip to content

Commit

Permalink
chore(backend): configure sentry for observability
Browse files Browse the repository at this point in the history
  • Loading branch information
tericcabrel committed Jun 3, 2024
1 parent e489380 commit 12e2e44
Show file tree
Hide file tree
Showing 24 changed files with 854 additions and 51 deletions.
2 changes: 1 addition & 1 deletion apps/backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ WEB_AUTH_ERROR_URL=http:https://localhost:7500/auth/error
SESSION_LIFETIME=90# 90 days
SENTRY_DSN=
SENTRY_ENABLED=false
SNIPPET_RENDERER_URL=http:https://localhost:3000/dev
SNIPPET_RENDERER_API_URL=http:https://localhost:3000/dev
46 changes: 24 additions & 22 deletions apps/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,34 +37,36 @@ yarn install
````
Create configuration file from the template
```shell
cp .env.template .env
cp .env.template .env.local

# Edit configuration to match your local environment and save
nano .env
nano .env.local
```

**Environment variables list**

| Variable | Description |
|----------------------|--------------------------------------------------------------------------|
| NODE_ENV | Node.js environment (default: development) |
| HOST | Host name where the application is running (default: http:https://localhost) |
| PORT | Port number of the application (default: 7501) |
| ENABLE_INTROSPECTION | Enable/Disable GraphQL introspection (must `false` in production) |
| DATABASE_URL | URL of the database |
| ADMIN_PASSWORD | Password of the default admin user. |
| CONVERTKIT_API_KEY | ConvertKit API key |
| CONVERTKIT_FORM_ID | ConvertKit Form ID |
| CONVERTKIT_TAG_ID | ConvertKit Tag ID |
| REQUEST_TIMEOUT | Max duration of a request (default: 30 seconds) |
| GITHUB_CLIENT_ID | GitHub application client ID for authentication with GitHub |
| GITHUB_CLIENT_SECRET | GitHub application client secret for authentication with GitHub |
| WEB_APP_URL | URL of the frontend the application that communicates with this app |
| WEB_AUTH_SUCCESS_URL | Callback URL of the frontend application when the authentication succeed |
| WEB_AUTH_ERROR_URL | Callback URL of the frontend application when the authentication failed |
| SESSION_LIFETIME | The session's lifetime when a user authenticate (default: 90 days) |
| SENTRY_DSN | Sentry DSN |
| SENTRY_ENABLED | Enable/Disable Sentry |
| Variable | Description |
|--------------------------|--------------------------------------------------------------------------------------|
| NODE_ENV | Node.js environment (default: development) |
| APP_VERSION | The current version of the application |
| HOST | Host name where the application is running (default: http:https://localhost) |
| PORT | Port number of the application (default: 7501) |
| ENABLE_INTROSPECTION | Enable/Disable GraphQL introspection (must `false` in production) |
| DATABASE_URL | URL of the database |
| ADMIN_PASSWORD | Password of the default admin user. |
| CONVERTKIT_API_KEY | ConvertKit API key |
| CONVERTKIT_FORM_ID | ConvertKit Form ID |
| CONVERTKIT_TAG_ID | ConvertKit Tag ID |
| REQUEST_TIMEOUT | Max duration of a request (default: 30 seconds) |
| GITHUB_CLIENT_ID | GitHub application client ID for authentication with GitHub |
| GITHUB_CLIENT_SECRET | GitHub application client secret for authentication with GitHub |
| WEB_APP_URL | URL of the frontend the application that communicates with this app |
| WEB_AUTH_SUCCESS_URL | Callback URL of the frontend application when the authentication succeed |
| WEB_AUTH_ERROR_URL | Callback URL of the frontend application when the authentication failed |
| SESSION_LIFETIME | The session's lifetime when a user authenticate (default: 90 days) |
| SENTRY_DSN | Sentry DSN |
| SENTRY_ENABLED | Enable/Disable Sentry |
| SNIPPET_RENDERER_API_URL | Base URL of the API (the current one) for generating the html content from a snippet |

Start the application
```bash
Expand Down
2 changes: 2 additions & 0 deletions apps/backend/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ export type EnvironmentVariables = {
GITHUB_CLIENT_ID: string;
GITHUB_CLIENT_SECRET: string;
HOST: string;
NODE_ENV: string;
PORT: string;
REQUEST_TIMEOUT: string;
SENTRY_DSN: string;
SENTRY_ENABLED: string;
SESSION_LIFETIME: string;
SNIPPET_RENDERER_URL: string;
WEB_APP_URL: string;
Expand Down
1 change: 1 addition & 0 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@nestjs/core": "10.3.8",
"@nestjs/platform-express": "10.3.8",
"@prisma/client": "5.14.0",
"@sentry/node": "8.3.0",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.1",
"zod": "3.23.8"
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import appConfig, { EnvironmentVariables, validate } from './configs/environment
controllers: [AppController],
imports: [
ConfigModule.forRoot({
envFilePath: ['.env', '.env.test'],
envFilePath: ['.env.local', '.env.test'],
isGlobal: true,
load: [appConfig],
validate,
Expand Down
4 changes: 4 additions & 0 deletions apps/backend/src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ export class AppService {

const roles = await this.roleService.findAll();

if (Math.random() > 0.5) {
throw new Error('[Data Loader]: Role administrator not found');
}

this.logger.log(roles);

return 'Hello World!';
Expand Down
8 changes: 8 additions & 0 deletions apps/backend/src/configs/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ export default registerAs('app', () => ({
env: process.env.NODE_ENV,
host: process.env.HOST,
port: parseInt(process.env.PORT ?? '7501', 10),
sentry: {
dsn: process.env.SENTRY_DSN,
enabled: process.env.SENTRY_ENABLED,
},
version: process.env.APP_VERSION,
}));

const EnvironmentVariablesSchema = z.object({
APP_VERSION: z.string(),
DATABASE_URL: z.string(),
HOST: z.string(),
NODE_ENV: z.union([z.literal('development'), z.literal('production'), z.literal('test')]),
PORT: z.number({ coerce: true }).min(7000).max(8000),
SENTRY_DSN: z.string(),
SENTRY_ENABLED: z.boolean({ coerce: true }),
});

export type EnvironmentVariables = z.infer<typeof EnvironmentVariablesSchema>;
Expand Down
22 changes: 22 additions & 0 deletions apps/backend/src/configs/instrument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as Sentry from '@sentry/node';

const isSentryEnabled = () => {
if (process.env.SENTRY_ENABLED !== 'true') {
return false;
}

return process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'development';
};

Sentry.init({
dsn: process.env.SENTRY_DSN,
enabled: isSentryEnabled(),
environment: process.env.NODE_ENV,
integrations: [Sentry.prismaIntegration()],
// https://docs.sentry.io/platforms/javascript/guides/nestjs/configuration/sampling/#setting-a-uniform-sample-rate
tracesSampleRate: 0.6,
});

Sentry.setContext('app', {
version: process.env.APP_VERSION,
});
9 changes: 8 additions & 1 deletion apps/backend/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import './configs/instrument';

import { Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import { BaseExceptionFilter, HttpAdapterHost, NestFactory } from '@nestjs/core';
import * as Sentry from '@sentry/node';

import { AppModule } from './app.module';
import { EnvironmentVariables } from './types/common';

const bootstrap = async () => {
const app = await NestFactory.create(AppModule);

const { httpAdapter } = app.get(HttpAdapterHost);

Sentry.setupNestErrorHandler(app, new BaseExceptionFilter(httpAdapter));

const configService = app.get(ConfigService<EnvironmentVariables, true>);
const logger = new Logger('NestApplication');

Expand Down
3 changes: 2 additions & 1 deletion apps/backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"composite": true,
"strictNullChecks": true
},
"files": ["env.d.ts"],
"include": [
"./src/**/*"
],
Expand All @@ -20,7 +21,7 @@
"path": "../../packages/utils"
},
{
"path": "../../packages/logger-old"
"path": "../../packages/domain"
}
]
}
2 changes: 1 addition & 1 deletion packages/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { DomainModule } from './src/domain.module';
export { PrismaService } from './src/prisma.service';
export { PrismaService } from './src/services/prisma.service';
export { UserService } from './src/services/users/user.service';
export { RoleService } from './src/services/roles/role.service';
export { FolderService } from './src/services/folders/folder.service';
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/domain.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DynamicModule, Module, Provider } from '@nestjs/common';

import { DOMAIN_SERVICES_OPTIONS } from './constants';
import { PrismaService } from './prisma.service';
import { FolderService } from './services/folders/folder.service';
import { NewsletterService } from './services/newsletters/newsletter.service';
import { PrismaService } from './services/prisma.service';
import { RoleService } from './services/roles/role.service';
import { SessionService } from './services/sessions/session.service';
import { SnippetService } from './services/snippets/snippet.service';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CreateFolderInput } from './inputs/create-folder-input';
import { CreateUserRootFolderInput } from './inputs/create-user-root-folder-input';
import { TestHelper } from '../../../tests/helpers';
import { DomainModule } from '../../domain.module';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';
import { RoleService } from '../roles/role.service';

describe('Test Folder service', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/services/folders/folder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CreateFolderInput } from './inputs/create-folder-input';
import { CreateUserRootFolderInput } from './inputs/create-user-root-folder-input';
import { UpdateFolderInput } from './inputs/update-folder-input';
import { isFoldersContainRoot } from './utils/folders';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';

@Injectable()
export class FolderService {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/domain/src/services/roles/role.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SnipcodeError, errors } from '@snipcode/utils';

import { CreateRoleInput } from './inputs/create-role-input';
import { Role, RoleName } from './role.entity';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';

@Injectable()
export class RoleService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Session } from './session.entity';
import { SessionService } from './session.service';
import { TestHelper } from '../../../tests/helpers';
import { DomainModule } from '../../domain.module';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';

describe('Test Session Service', function () {
let sessionService: SessionService;
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/services/sessions/session.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';

import { CreateSessionInput } from './inputs/create-session-input';
import { Session } from './session.entity';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';

@Injectable()
export class SessionService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Snippet } from './snippet.entity';
import { SnippetService } from './snippet.service';
import { TestHelper } from '../../../tests/helpers';
import { DomainModule } from '../../domain.module';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';
import { RoleService } from '../roles/role.service';

describe('Test Snippet service', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/services/snippets/snippet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CreateSnippetInput } from './inputs/create-snippet-input';
import { DeleteSnippetInput } from './inputs/delete-snippet-input';
import { UpdateSnippetInput } from './inputs/update-snippet-input';
import { Snippet, SnippetVisibility } from './snippet.entity';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';

const MAX_ITEM_PER_PAGE = 50;

Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/services/users/user.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { User } from './user.entity';
import { UserService } from './user.service';
import { TestHelper } from '../../../tests/helpers';
import { DomainModule } from '../../domain.module';
import { PrismaService } from '../../prisma.service';
import { PrismaService } from '../prisma.service';
import { RoleService } from '../roles/role.service';

describe('Test User service', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/src/services/users/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { generateFromEmail } from 'unique-username-generator';
import { CreateUserInput } from './inputs/create-user-input';
import { UpdateUserInput } from './inputs/update-user-input';
import { User } from './user.entity';
import { PrismaService } from '../../prisma.service';
import { CreateUserRootFolderInput } from '../folders/inputs/create-user-root-folder-input';
import { PrismaService } from '../prisma.service';
import { Role } from '../roles/role.entity';

@Injectable()
Expand Down
2 changes: 1 addition & 1 deletion packages/domain/tests/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { randEmail, randFullName, randImg, randNumber, randTimeZone, randUserName, randWord } from '@ngneat/falso';

import { PrismaService } from '../src/prisma.service';
import { Folder } from '../src/services/folders/folder.entity';
import { CreateFolderInput } from '../src/services/folders/inputs/create-folder-input';
import { CreateUserRootFolderInput } from '../src/services/folders/inputs/create-user-root-folder-input';
import { UpdateFolderInput } from '../src/services/folders/inputs/update-folder-input';
import { PrismaService } from '../src/services/prisma.service';
import { Role, RoleName } from '../src/services/roles/role.entity';
import { CreateSessionInput } from '../src/services/sessions/inputs/create-session-input';
import { Session } from '../src/services/sessions/session.entity';
Expand Down

0 comments on commit 12e2e44

Please sign in to comment.