Skip to content

Commit aed082e

Browse files
feat: setup sentry for the controlplane (#2199)
1 parent 106e871 commit aed082e

File tree

6 files changed

+756
-10
lines changed

6 files changed

+756
-10
lines changed

controlplane/.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,11 @@ PROMETHEUS_ENABLED="false"
7474
PROMETHEUS_HTTP_PATH="/metrics"
7575
PROMETHEUS_PORT="8088"
7676
PROMETHEUS_HOST="localhost"
77+
78+
# Sentry integration
79+
SENTRY_ENABLED="false"
80+
SENTRY_DSN=""
81+
SENTRY_SEND_DEFAULT_PII="false"
82+
SENTRY_TRACES_SAMPLE_RATE="1.0"
83+
SENTRY_PROFILE_SESSION_SAMPLE_RATE="1.0"
84+
SENTRY_EVENT_LOOP_BLOCK_THRESHOLD_MS="100"

controlplane/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
"@graphql-tools/utils": "^10.1.2",
5252
"@keycloak/keycloak-admin-client": "^25.0.2",
5353
"@octokit/webhooks-types": "^7.6.1",
54+
"@sentry/node": "^10.11.0",
55+
"@sentry/node-native": "^10.11.0",
56+
"@sentry/profiling-node": "^10.11.0",
5457
"@tiptap/core": "^2.1.13",
5558
"@wundergraph/composition": "workspace:*",
5659
"@wundergraph/cosmo-connect": "workspace:*",
@@ -116,4 +119,4 @@
116119
"typescript": "5.5.2",
117120
"vitest": "^3.2.4"
118121
}
119-
}
122+
}

controlplane/src/core/env.schema.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,24 @@ export const envVariables = z
178178
* Admission Webhook
179179
*/
180180
AUTH_ADMISSION_JWT_SECRET: z.string(),
181+
182+
/**
183+
* Sentry
184+
*/
185+
SENTRY_ENABLED: z
186+
.string()
187+
.optional()
188+
.transform((val) => val === 'true')
189+
.default('false'),
190+
SENTRY_DSN: z.string().optional(),
191+
SENTRY_SEND_DEFAULT_PII: z
192+
.string()
193+
.optional()
194+
.transform((val) => val === 'true')
195+
.default('false'),
196+
SENTRY_TRACES_SAMPLE_RATE: z.coerce.number().optional().default(1),
197+
SENTRY_PROFILE_SESSION_SAMPLE_RATE: z.coerce.number().optional().default(1),
198+
SENTRY_EVENT_LOOP_BLOCK_THRESHOLD_MS: z.coerce.number().optional().default(100),
181199
})
182200
.refine((input) => {
183201
if (input.STRIPE_WEBHOOK_SECRET && !input.STRIPE_SECRET_KEY) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// sentry.config.ts
2+
import * as Sentry from '@sentry/node';
3+
4+
import { nodeProfilingIntegration } from '@sentry/profiling-node';
5+
import { eventLoopBlockIntegration } from '@sentry/node-native';
6+
7+
export interface SentryConfig {
8+
sentry: {
9+
enabled: boolean;
10+
dsn: string;
11+
eventLoopBlockIntegrationThresholdMs?: number;
12+
profileSessionSampleRate?: number;
13+
sendDefaultPii?: boolean;
14+
tracesSampleRate?: number;
15+
};
16+
}
17+
18+
export function init(opts: SentryConfig) {
19+
if (opts.sentry.enabled) {
20+
Sentry.init({
21+
dsn: opts.sentry.dsn,
22+
integrations: [
23+
eventLoopBlockIntegration({ threshold: opts.sentry.eventLoopBlockIntegrationThresholdMs }),
24+
nodeProfilingIntegration(),
25+
],
26+
profileSessionSampleRate: opts.sentry.profileSessionSampleRate,
27+
sendDefaultPii: opts.sentry.sendDefaultPii,
28+
tracesSampleRate: opts.sentry.tracesSampleRate,
29+
});
30+
}
31+
}

controlplane/src/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'dotenv/config';
55

66
import build, { BuildConfig } from './core/build-server.js';
77
import { envVariables } from './core/env.schema.js';
8+
import { SentryConfig } from './core/sentry.config.js';
89

910
const {
1011
LOG_LEVEL,
@@ -66,6 +67,12 @@ const {
6667
REDIS_PASSWORD,
6768
AUTH_ADMISSION_JWT_SECRET,
6869
CDN_BASE_URL,
70+
SENTRY_ENABLED,
71+
SENTRY_DSN,
72+
SENTRY_SEND_DEFAULT_PII,
73+
SENTRY_TRACES_SAMPLE_RATE,
74+
SENTRY_PROFILE_SESSION_SAMPLE_RATE,
75+
SENTRY_EVENT_LOOP_BLOCK_THRESHOLD_MS,
6976
} = envVariables.parse(process.env);
7077

7178
const options: BuildConfig = {
@@ -170,6 +177,24 @@ if (STRIPE_SECRET_KEY) {
170177
};
171178
}
172179

180+
if (SENTRY_ENABLED) {
181+
if (SENTRY_DSN) {
182+
const sentryConfig: SentryConfig = {
183+
sentry: {
184+
enabled: SENTRY_ENABLED,
185+
dsn: SENTRY_DSN,
186+
eventLoopBlockIntegrationThresholdMs: SENTRY_EVENT_LOOP_BLOCK_THRESHOLD_MS,
187+
profileSessionSampleRate: SENTRY_PROFILE_SESSION_SAMPLE_RATE,
188+
sendDefaultPii: SENTRY_SEND_DEFAULT_PII,
189+
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
190+
},
191+
};
192+
await import('./core/sentry.config.js').then((sentry) => sentry.init(sentryConfig));
193+
} else {
194+
throw new Error('SENTRY_ENABLED is set but SENTRY_DSN is not');
195+
}
196+
}
197+
173198
const app = await build(options);
174199

175200
await app.listen({

0 commit comments

Comments
 (0)