feat: set sentry

This commit is contained in:
Nevo David 2025-07-30 19:50:05 +07:00
parent 0fa950dd8e
commit 3483b022e8
25 changed files with 1336 additions and 124 deletions

View File

@ -11,10 +11,13 @@ import { AgentModule } from '@gitroom/nestjs-libraries/agent/agent.module';
import { McpModule } from '@gitroom/backend/mcp/mcp.module';
import { ThirdPartyModule } from '@gitroom/nestjs-libraries/3rdparties/thirdparty.module';
import { VideoModule } from '@gitroom/nestjs-libraries/videos/video.module';
import { SentryModule } from "@sentry/nestjs/setup";
import { FILTER } from '@gitroom/nestjs-libraries/sentry/sentry.exception';
@Global()
@Module({
imports: [
SentryModule.forRoot(),
BullMqModule,
DatabaseModule,
ApiModule,
@ -32,6 +35,7 @@ import { VideoModule } from '@gitroom/nestjs-libraries/videos/video.module';
],
controllers: [],
providers: [
FILTER,
{
provide: APP_GUARD,
useClass: ThrottlerBehindProxyGuard,
@ -39,7 +43,7 @@ import { VideoModule } from '@gitroom/nestjs-libraries/videos/video.module';
{
provide: APP_GUARD,
useClass: PoliciesGuard,
},
}
],
exports: [
BullMqModule,

View File

@ -9,6 +9,9 @@ import { AppModule } from './app.module';
import { SubscriptionExceptionFilter } from '@gitroom/backend/services/auth/permissions/subscription.exception';
import { HttpExceptionFilter } from '@gitroom/nestjs-libraries/services/exception.filter';
import { ConfigurationChecker } from '@gitroom/helpers/configuration/configuration.checker';
import { initializeSentry } from '@gitroom/nestjs-libraries/sentry/initialize.sentry';
initializeSentry();
async function bootstrap() {
const app = await NestFactory.create(AppModule, {

View File

@ -1,13 +1,20 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { CheckStars } from '@gitroom/cron/tasks/check.stars';
import { DatabaseModule } from '@gitroom/nestjs-libraries/database/prisma/database.module';
import { SyncTrending } from '@gitroom/cron/tasks/sync.trending';
import { BullMqModule } from '@gitroom/nestjs-libraries/bull-mq-transport-new/bull.mq.module';
import { SentryModule } from '@sentry/nestjs/setup';
import { FILTER } from '@gitroom/nestjs-libraries/sentry/sentry.exception';
@Module({
imports: [DatabaseModule, ScheduleModule.forRoot(), BullMqModule],
imports: [
SentryModule.forRoot(),
DatabaseModule,
ScheduleModule.forRoot(),
BullMqModule,
],
controllers: [],
providers: [...(!process.env.IS_GENERAL ? [CheckStars, SyncTrending] : [])],
providers: [
FILTER
],
})
export class CronModule {}

View File

@ -1,5 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { CronModule } from './cron.module';
import { initializeSentry } from '@gitroom/nestjs-libraries/sentry/initialize.sentry';
initializeSentry();
async function bootstrap() {
// some comment again

View File

View File

@ -1,23 +0,0 @@
import { Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { StarsService } from '@gitroom/nestjs-libraries/database/prisma/stars/stars.service';
import { BullMqClient } from '@gitroom/nestjs-libraries/bull-mq-transport-new/client';
@Injectable()
export class CheckStars {
constructor(
private _starsService: StarsService,
private _workerServiceProducer: BullMqClient
) {}
@Cron('30 0 * * *')
async checkStars() {
const allGitHubRepositories =
await this._starsService.getAllGitHubRepositories();
for (const repository of allGitHubRepositories) {
this._workerServiceProducer.emit('check_stars', {
payload: { login: repository.login },
});
}
}
}

View File

@ -1,12 +0,0 @@
import { Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { BullMqClient } from '@gitroom/nestjs-libraries/bull-mq-transport-new/client';
@Injectable()
export class SyncTrending {
constructor(private _workerServiceProducer: BullMqClient) {}
@Cron('0 * * * *')
async syncTrending() {
this._workerServiceProducer.emit('sync_trending', {}).subscribe();
}
}

View File

@ -1,4 +1,6 @@
// @ts-check
import { withSentryConfig } from '@sentry/nextjs';
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
@ -40,4 +42,10 @@ const nextConfig = {
];
},
};
export default nextConfig;
export default !!process.env.SENTRY_ORG
? withSentryConfig(nextConfig, {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
})
: nextConfig;

View File

@ -1,3 +1,5 @@
import { SentryComponent } from '@gitroom/frontend/components/layout/sentry.component';
export const dynamic = 'force-dynamic';
import '../global.scss';
import 'react-tooltip/dist/react-tooltip.css';
@ -33,7 +35,9 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
<head>
<link rel="icon" href="/favicon.ico" sizes="any" />
</head>
<body className={clsx(jakartaSans.className, 'dark text-primary !bg-primary')}>
<body
className={clsx(jakartaSans.className, 'dark text-primary !bg-primary')}
>
<HtmlComponent />
<VariableContextComponent
storageProvider={
@ -56,6 +60,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
isSecured={!process.env.NOT_SECURED}
disableImageCompression={!!process.env.DISABLE_IMAGE_COMPRESSION}
disableXAnalytics={!!process.env.DISABLE_X_ANALYTICS}
sentryDsn={process.env.NEXT_PUBLIC_SENTRY_DSN!}
language={allHeaders.get(headerName)}
transloadit={
process.env.TRANSLOADIT_AUTH && process.env.TRANSLOADIT_TEMPLATE
@ -66,21 +71,23 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
: []
}
>
<ToltScript />
<FacebookComponent />
<Plausible
domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'}
>
<PHProvider
phkey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
host={process.env.NEXT_PUBLIC_POSTHOG_HOST}
<SentryComponent>
<ToltScript />
<FacebookComponent />
<Plausible
domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'}
>
<LayoutContext>
<UtmSaver />
{children}
</LayoutContext>
</PHProvider>
</Plausible>
<PHProvider
phkey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
host={process.env.NEXT_PUBLIC_POSTHOG_HOST}
>
<LayoutContext>
<UtmSaver />
{children}
</LayoutContext>
</PHProvider>
</Plausible>
</SentryComponent>
</VariableContextComponent>
</body>
</html>

View File

@ -44,6 +44,7 @@ export default async function AppLayout({ children }: { children: ReactNode }) {
isSecured={!process.env.NOT_SECURED}
disableImageCompression={!!process.env.DISABLE_IMAGE_COMPRESSION}
disableXAnalytics={!!process.env.DISABLE_X_ANALYTICS}
sentryDsn={process.env.NEXT_PUBLIC_SENTRY_DSN!}
transloadit={
process.env.TRANSLOADIT_AUTH && process.env.TRANSLOADIT_TEMPLATE
? [

View File

@ -0,0 +1,21 @@
'use client';
import * as Sentry from '@sentry/nextjs';
import NextError from 'next/error';
import { useEffect } from 'react';
export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<NextError statusCode={0} />
</body>
</html>
);
}

View File

@ -0,0 +1,24 @@
'use client';
import { FC, ReactNode, useEffect } from 'react';
import { useVariables } from '@gitroom/react/helpers/variable.context';
import { initializeSentryClient } from '@gitroom/react/sentry/initialize.sentry.client';
export const SentryComponent: FC<{ children: ReactNode }> = ({ children }) => {
const { sentryDsn: dsn } = useVariables();
useEffect(() => {
if (!dsn) {
return ;
}
try {
initializeSentryClient(dsn);
} catch (error) {
console.error('[Sentry] Configuration error:', error);
}
}, [dsn]);
// Always render children - don't block the app
return <>{children}</>;
};

View File

@ -0,0 +1,11 @@
export async function register() {
if (!process.env.NEXT_PUBLIC_SENTRY_DSN) {
return;
}
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./sentry.server.config');
}
if (process.env.NEXT_RUNTIME === 'edge') {
await import('./sentry.edge.config');
}
}

View File

@ -0,0 +1,3 @@
import { initializeSentryServer } from '@gitroom/react/sentry/initialize.sentry.server';
initializeSentryServer(process.env.NEXT_PUBLIC_SENTRY_DSN);

View File

@ -0,0 +1,3 @@
import { initializeSentryServer } from '@gitroom/react/sentry/initialize.sentry.server';
initializeSentryServer(process.env.NEXT_PUBLIC_SENTRY_DSN);

View File

@ -1,17 +1,15 @@
import { Module } from '@nestjs/common';
import { DatabaseModule } from '@gitroom/nestjs-libraries/database/prisma/database.module';
import { TrendingService } from '@gitroom/nestjs-libraries/services/trending.service';
import { PostsController } from '@gitroom/workers/app/posts.controller';
import { BullMqModule } from '@gitroom/nestjs-libraries/bull-mq-transport-new/bull.mq.module';
import { PlugsController } from '@gitroom/workers/app/plugs.controller';
import { SentryModule } from '@sentry/nestjs/setup';
import { FILTER } from '@gitroom/nestjs-libraries/sentry/sentry.exception';
@Module({
imports: [DatabaseModule, BullMqModule],
controllers: [
PostsController,
PlugsController,
],
providers: [TrendingService],
imports: [SentryModule.forRoot(), DatabaseModule, BullMqModule],
controllers: [PostsController, PlugsController],
providers: [FILTER],
})
export class AppModule {}

View File

@ -3,6 +3,9 @@ import { NestFactory } from '@nestjs/core';
import { AppModule } from './app/app.module';
import { MicroserviceOptions } from '@nestjs/microservices';
import { BullMqServer } from '@gitroom/nestjs-libraries/bull-mq-transport-new/strategy';
import { initializeSentry } from '@gitroom/nestjs-libraries/sentry/initialize.sentry';
initializeSentry();
async function bootstrap() {
process.env.IS_WORKER = 'true';

View File

@ -0,0 +1,21 @@
import * as Sentry from '@sentry/nestjs';
import { nodeProfilingIntegration } from "@sentry/profiling-node";
export const initializeSentry = () => {
if (!process.env.NEXT_PUBLIC_SENTRY_DSN) {
return null;
}
console.log('loading sentry');
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
integrations: [
// Add our Profiling integration
nodeProfilingIntegration(),
],
tracesSampleRate: 1.0,
profilesSampleRate: 1.0,
});
return true;
};

View File

@ -0,0 +1,7 @@
import { APP_FILTER } from "@nestjs/core";
import { SentryGlobalFilter } from "@sentry/nestjs/setup";
export const FILTER = {
provide: APP_FILTER,
useClass: SentryGlobalFilter,
};

View File

@ -22,6 +22,7 @@ interface VariableContextInterface {
language: string;
tolt: string;
transloadit: string[];
sentryDsn: string;
}
const VariableContext = createContext({
billingEnabled: false,
@ -44,6 +45,7 @@ const VariableContext = createContext({
language: '',
tolt: '',
transloadit: [],
sentryDsn: '',
} as VariableContextInterface);
export const VariableContextComponent: FC<
VariableContextInterface & {

View File

@ -0,0 +1,17 @@
import * as Sentry from '@sentry/nextjs';
import { initializeSentryBasic } from '@gitroom/react/sentry/initialize.sentry.next.basic';
export const initializeSentryClient = (dsn: string) =>
initializeSentryBasic(dsn, {
integrations: [
// Add default integrations back
Sentry.browserTracingIntegration(),
Sentry.replayIntegration({
maskAllText: true,
maskAllInputs: true,
}),
],
replaysSessionSampleRate:
process.env.NODE_ENV === 'development' ? 1.0 : 0.1,
replaysOnErrorSampleRate: 1.0,
});

View File

@ -0,0 +1,28 @@
import * as Sentry from '@sentry/nextjs';
export const initializeSentryBasic = (dsn: string, extension: any) => {
if (!dsn) {
return;
}
Sentry.init({
initialScope: {
tags: {
service: 'frontend',
component: 'nextjs',
replaysEnabled: 'true',
},
contexts: {
app: {
name: 'Postiz Frontend',
version: process.env.NEXT_PUBLIC_APP_VERSION || '0.0.0',
},
},
},
dsn,
sendDefaultPii: true,
...extension,
debug: process.env.NODE_ENV === 'development',
tracesSampleRate: process.env.NODE_ENV === 'development' ? 1.0 : 0.1,
});
};

View File

@ -0,0 +1,5 @@
import * as Sentry from '@sentry/nextjs';
import { initializeSentryBasic } from '@gitroom/react/sentry/initialize.sentry.next.basic';
export const initializeSentryServer = (dsn: string) =>
initializeSentryBasic(dsn, {});

View File

@ -73,6 +73,9 @@
"@neynar/react": "^0.9.7",
"@postiz/wallets": "^0.0.1",
"@prisma/client": "^6.5.0",
"@sentry/nestjs": "^9.43.0",
"@sentry/nextjs": "^9.43.0",
"@sentry/profiling-node": "^9.43.0",
"@solana/wallet-adapter-react": "^0.15.35",
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@swc/helpers": "0.5.13",

File diff suppressed because it is too large Load Diff