From 83d59df57ba3810e9e0b37aba2e708929ed32f43 Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Thu, 9 Jul 2026 21:58:23 -0700 Subject: [PATCH 1/3] feat(web): enable Sentry node and browser profiling Adds @sentry/profiling-node and wires up profiling on both the server (nodeProfilingIntegration) and the browser (browserProfilingIntegration). Both use profileLifecycle: 'trace', so a profiler only runs while a sampled root span is active rather than continuously. Browser profiling additionally requires the document to opt into the JS Self-Profiling API, so a `Document-Policy: js-profiling` response header is added alongside the existing security headers. @sentry/profiling-node is pinned to ^10.40.0 to match @sentry/nextjs. It depends on @sentry/core and @sentry/node at exact versions, so a newer minor would pull a second copy of the SDK into the tree and the profiler would register against a different global. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/web/next.config.mjs | 7 +++++++ packages/web/package.json | 1 + packages/web/src/instrumentation-client.ts | 11 +++++++---- packages/web/src/sentry.server.config.ts | 12 ++++++++---- yarn.lock | 1 + 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/web/next.config.mjs b/packages/web/next.config.mjs index 953fd480f..e153f11ef 100644 --- a/packages/web/next.config.mjs +++ b/packages/web/next.config.mjs @@ -104,6 +104,13 @@ const nextConfig = { key: "Content-Security-Policy", value: "frame-ancestors 'self'", }, + // Opts the document into the JS Self-Profiling API, which Sentry's + // browser profiling integration needs in order to start a profiler. + // @see: https://docs.sentry.io/platforms/javascript/guides/nextjs/profiling/browser-profiling/ + { + key: "Document-Policy", + value: "js-profiling", + }, ], }, ]; diff --git a/packages/web/package.json b/packages/web/package.json index abd1756aa..64977cd67 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -102,6 +102,7 @@ "@replit/codemirror-lang-svelte": "^6.0.0", "@replit/codemirror-vim": "^6.2.1", "@sentry/nextjs": "^10.40.0", + "@sentry/profiling-node": "^10.40.0", "@shopify/lang-jsonc": "^1.0.0", "@sourcebot/codemirror-lang-tcl": "^1.0.13", "@sourcebot/db": "workspace:*", diff --git a/packages/web/src/instrumentation-client.ts b/packages/web/src/instrumentation-client.ts index 07dc43073..fb0ff0171 100644 --- a/packages/web/src/instrumentation-client.ts +++ b/packages/web/src/instrumentation-client.ts @@ -12,11 +12,14 @@ if (!!process.env.NEXT_PUBLIC_SENTRY_WEBAPP_DSN && !!process.env.NEXT_PUBLIC_SEN Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_WEBAPP_DSN, environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT, - + integrations: [ + Sentry.browserProfilingIntegration(), + ], tracesSampleRate: 1.0, - - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, + // Evaluated once per `Sentry.init()`, i.e. once per page load. + profileSessionSampleRate: 1.0, + // Profile only while a sampled root span is active, rather than continuously. + profileLifecycle: 'trace', }); } else { console.debug("[client] Sentry was not initialized"); diff --git a/packages/web/src/sentry.server.config.ts b/packages/web/src/sentry.server.config.ts index c51b7246c..cd7d6b98d 100644 --- a/packages/web/src/sentry.server.config.ts +++ b/packages/web/src/sentry.server.config.ts @@ -3,6 +3,7 @@ // https://docs.sentry.io/platforms/javascript/guides/nextjs/ import * as Sentry from "@sentry/nextjs"; +import { nodeProfilingIntegration } from "@sentry/profiling-node"; import { createLogger } from "@sourcebot/shared"; const logger = createLogger('sentry-server-config'); @@ -11,11 +12,14 @@ if (!!process.env.NEXT_PUBLIC_SENTRY_WEBAPP_DSN && !!process.env.NEXT_PUBLIC_SEN Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_WEBAPP_DSN, environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT, - + integrations: [ + nodeProfilingIntegration(), + ], tracesSampleRate: 1.0, - - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, + // Evaluated once per `Sentry.init()`, i.e. once per server process. + profileSessionSampleRate: 1.0, + // Profile only while a sampled root span is active, rather than continuously. + profileLifecycle: 'trace', }); } else { logger.debug("[server] Sentry was not initialized"); diff --git a/yarn.lock b/yarn.lock index a5b222729..e6c43bd60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9380,6 +9380,7 @@ __metadata: "@replit/codemirror-lang-svelte": "npm:^6.0.0" "@replit/codemirror-vim": "npm:^6.2.1" "@sentry/nextjs": "npm:^10.40.0" + "@sentry/profiling-node": "npm:^10.40.0" "@shopify/lang-jsonc": "npm:^1.0.0" "@sourcebot/codemirror-lang-tcl": "npm:^1.0.13" "@sourcebot/db": "workspace:*" From 2947a3379a095a129f6403754959b4f0ca3d76d7 Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Thu, 9 Jul 2026 21:59:21 -0700 Subject: [PATCH 2/3] docs: add CHANGELOG entry for Sentry profiling Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b54760680..094f7a18a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [EE] Added image attachments to Ask Sourcebot, letting users attach images to a chat message when the selected model supports image input. [#1375](https://github.com/sourcebot-dev/sourcebot/pull/1375) - Added deployment system resource stats (CPU cores + cgroup quota, host + container memory, disk, load average) to the service ping, so resource issues can be diagnosed more quickly. [#1424](https://github.com/sourcebot-dev/sourcebot/pull/1424) - Added a `robots.txt` that disallows crawlers, with an allowlist for link-preview bots so shared links keep their OpenGraph previews. [#1426](https://github.com/sourcebot-dev/sourcebot/pull/1426) +- Added Sentry node and browser profiling to the web app. [#1431](https://github.com/sourcebot-dev/sourcebot/pull/1431) ### Fixed - Send anonymous server-side PostHog events as personless so unauthenticated requests don't inflate person counts. [#1367](https://github.com/sourcebot-dev/sourcebot/pull/1367) From a992a8064d9162d86239b6a12609bb7a2db05cca Mon Sep 17 00:00:00 2001 From: Brendan Kellam Date: Thu, 9 Jul 2026 22:00:43 -0700 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 094f7a18a..b54760680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [EE] Added image attachments to Ask Sourcebot, letting users attach images to a chat message when the selected model supports image input. [#1375](https://github.com/sourcebot-dev/sourcebot/pull/1375) - Added deployment system resource stats (CPU cores + cgroup quota, host + container memory, disk, load average) to the service ping, so resource issues can be diagnosed more quickly. [#1424](https://github.com/sourcebot-dev/sourcebot/pull/1424) - Added a `robots.txt` that disallows crawlers, with an allowlist for link-preview bots so shared links keep their OpenGraph previews. [#1426](https://github.com/sourcebot-dev/sourcebot/pull/1426) -- Added Sentry node and browser profiling to the web app. [#1431](https://github.com/sourcebot-dev/sourcebot/pull/1431) ### Fixed - Send anonymous server-side PostHog events as personless so unauthenticated requests don't inflate person counts. [#1367](https://github.com/sourcebot-dev/sourcebot/pull/1367)