feat: connect sentry to dash and api

This commit is contained in:
Rotimi Best
2026-05-21 17:18:08 +01:00
parent 25a4b1fd19
commit 0657c32c97
14 changed files with 1134 additions and 131 deletions
+9
View File
@@ -1,5 +1,6 @@
import 'dotenv/config';
import * as Sentry from '@sentry/node';
import { consumeHandoffPayload, storeHandoffPayload } from '@api/utils/redis/oauth-handoff';
import { isPublicCorsPath, sessionCors } from '@api/middlewares/cors';
import { randomBytes } from 'crypto';
@@ -78,6 +79,13 @@ export const app = new Hono()
c.set('user', session.user);
c.set('session', session.session);
c.set('orgRoles', (session as { orgRoles?: Record<string, number> }).orgRoles ?? {});
Sentry.setUser({
id: session.user.id,
...(session.user.email && { email: session.user.email }),
...(session.user.name && { username: session.user.name })
});
await next();
})
@@ -206,6 +214,7 @@ export const app = new Hono()
// Error handling
.onError((err, c) => {
Sentry.captureException(err);
console.error('Error:', err);
return c.json({ error: 'Internal Server Error' }, 500);
});
+4
View File
@@ -78,6 +78,10 @@ const envSchema = z.object({
return Number.isFinite(parsed) && parsed >= 1 ? Math.trunc(parsed) : 15;
}),
/** Sentry error tracking (server-side). Leave SENTRY_DSN unset to disable. */
SENTRY_DSN: z.string().optional(),
SENTRY_ENVIRONMENT: z.string().optional(),
SENTRY_TRACES_SAMPLE_RATE: z.string().optional(),
/** Max fetch_documentation_url calls per org per UTC day (default 500). */
AGENT_MAX_FETCHES_PER_ORG_PER_DAY: z
.string()
+1
View File
@@ -1,4 +1,5 @@
import 'dotenv/config';
import './instrument';
import { API_PORT } from '@api/constants';
import { app } from '@api/app';
+20
View File
@@ -0,0 +1,20 @@
/**
* Must be imported as the FIRST thing in `apps/api/src/index.ts`. The Sentry
* Node SDK relies on auto-instrumentation that hooks into Node's `require`
* resolution and module loaders; any code that runs before this file initializes
* Sentry will not be traced.
*/
import * as Sentry from '@sentry/node';
const dsn = process.env.SENTRY_DSN?.trim();
const isProd = process.env.NODE_ENV === 'production';
const isSelfHosted = process.env.PUBLIC_IS_SELFHOSTED === 'true';
if (dsn && isProd && !isSelfHosted) {
Sentry.init({
dsn,
environment: process.env.SENTRY_ENVIRONMENT?.trim() || 'production',
tracesSampleRate: Number(process.env.SENTRY_TRACES_SAMPLE_RATE ?? 0),
sendDefaultPii: false
});
}