chore(observability): replace Sentry with PostHog error tracking#1859
chore(observability): replace Sentry with PostHog error tracking#1859
Conversation
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughRemoved Sentry token from CI deploy step and replaced event-based PostHog error reporting with a new direct Changes
Sequence DiagramsequenceDiagram
participant App as Backend App
participant Handler as capturePosthogException
participant Parser as parseExceptionFrames
participant PostHog as PostHog API
App->>Handler: send error, request, kind
Handler->>Handler: validate POSTHOG_API_KEY & POSTHOG_API_HOST
Handler->>Parser: parse error.stack -> frames
Parser-->>Handler: frames
Handler->>Handler: compute $exception_fingerprint & build payload (token,timestamp,properties)
Handler->>PostHog: POST /i/v0/e/ (JSON) with AbortSignal (5s)
PostHog-->>Handler: 200 OK / error
Handler-->>App: return true / false (log result)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
supabase/functions/_backend/utils/posthog.ts (1)
140-164: Minor:parseExceptionFramesis called twice with identical arguments.The function is invoked once at line 140 (for fingerprinting) and again at line 164 (for the exception payload). Consider caching the result to avoid redundant stack parsing.
♻️ Suggested fix
const serializedError = serializeError(payload.error) const distinctId = `backend:${getEnv(c, 'ENV_NAME') || 'unknown'}:${payload.functionName}` - const topFrame = parseExceptionFrames(serializedError.stack, payload.functionName)[0] + const frames = parseExceptionFrames(serializedError.stack, payload.functionName) + const topFrame = frames[0] const fingerprint = [ distinctId, payload.kind,Then at line 164:
stacktrace: { type: 'raw', - frames: parseExceptionFrames(serializedError.stack, payload.functionName), + frames, },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@supabase/functions/_backend/utils/posthog.ts` around lines 140 - 164, The code calls parseExceptionFrames(serializedError.stack, payload.functionName) twice (once to compute topFrame for fingerprinting and again for the body.stacktrace); compute it once into a local variable (e.g., frames = parseExceptionFrames(serializedError.stack, payload.functionName)), reuse frames when deriving topFrame and when populating body.properties.$exception_list[0].stacktrace.frames; update references to topFrame to use frames[0] and replace the second call with the cached frames variable to avoid redundant parsing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@supabase/functions/_backend/utils/posthog.ts`:
- Around line 140-164: The code calls
parseExceptionFrames(serializedError.stack, payload.functionName) twice (once to
compute topFrame for fingerprinting and again for the body.stacktrace); compute
it once into a local variable (e.g., frames =
parseExceptionFrames(serializedError.stack, payload.functionName)), reuse frames
when deriving topFrame and when populating
body.properties.$exception_list[0].stacktrace.frames; update references to
topFrame to use frames[0] and replace the second call with the cached frames
variable to avoid redundant parsing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 418a845e-e76b-45ab-8c5a-925309641ff7
⛔ Files ignored due to path filters (2)
bun.lockis excluded by!**/*.locksupabase/functions/deno.lockis excluded by!**/*.lock
📒 Files selected for processing (29)
.github/workflows/build_and_deploy.ymlcloudflare_workers/api/index.tscloudflare_workers/files/index.tscloudflare_workers/plugin/index.tspackage.jsonsupabase/functions/_backend/utils/hono.tssupabase/functions/_backend/utils/on_error.tssupabase/functions/_backend/utils/posthog.tssupabase/functions/apikey/index.tssupabase/functions/app/index.tssupabase/functions/build/index.tssupabase/functions/bundle/index.tssupabase/functions/channel/index.tssupabase/functions/channel_self/index.tssupabase/functions/deno.jsonsupabase/functions/device/index.tssupabase/functions/files/index.tssupabase/functions/ok/index.tssupabase/functions/organization/index.tssupabase/functions/private/index.tssupabase/functions/replication/index.tssupabase/functions/statistics/index.tssupabase/functions/stats/index.tssupabase/functions/triggers/index.tssupabase/functions/updates/index.tssupabase/functions/updates_debug/index.tssupabase/functions/webhooks/index.tstests/on-error-posthog.unit.test.tstests/posthog.unit.test.ts
💤 Files with no reviewable changes (2)
- supabase/functions/deno.json
- .github/workflows/build_and_deploy.yml
…osthog # Conflicts: # supabase/functions/_backend/utils/posthog.ts # tests/posthog.unit.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ffded9a498
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
supabase/functions/_backend/utils/posthog.ts (1)
96-101: Preserve parsed function name in fallback frames.When filename/line parsing fails, Line 98 currently drops
functionNameand replaces it withfallbackFunctionName, which reduces stack fidelity.Proposed tweak
if (lastColonIndex === -1 || secondLastColonIndex === -1) { return { - function: fallbackFunctionName, + function: functionName || fallbackFunctionName, platform: 'custom', lang: 'javascript', } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@supabase/functions/_backend/utils/posthog.ts` around lines 96 - 101, The fallback branch currently discards the parsed functionName and always sets function to fallbackFunctionName; instead, preserve any existing parsed functionName and only use fallbackFunctionName when functionName is empty. Update the return in the block guarded by lastColonIndex/secondLastColonIndex to set function to functionName || fallbackFunctionName (or otherwise prefer functionName when present), keeping platform and lang as-is; reference the variables lastColonIndex, secondLastColonIndex, fallbackFunctionName, and functionName to locate and fix the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@supabase/functions/_backend/utils/posthog.ts`:
- Around line 136-137: The call to getPostHogExceptionUrl(host) may throw for a
malformed POSTHOG_API_HOST and should be guarded so error reporting doesn't fail
before the surrounding try/catch; wrap the call to getPostHogExceptionUrl in a
try/catch (or validate host first) and on error fallback to
POSTHOG_EXCEPTION_URL or null, assign safely to posthogUrl, and ensure
subsequent fetch logic in this module (uses posthogUrl) handles a null/undefined
URL so the reporting path continues without throwing; reference the host
variable, getEnv(c, 'POSTHOG_API_HOST'), getPostHogExceptionUrl,
POSTHOG_EXCEPTION_URL, and posthogUrl when making the change.
- Around line 171-175: The exception properties currently send the full request
URL (url: c.req.url) which can leak query params/fragments; change this to only
include the path component (e.g., use the request pathname) or a sanitized URL
without query/fragment before adding to the payload. Locate the object that sets
method/request_id/status/url (the code referencing c.req.method,
c.get('requestId'), payload.status, c.req.url) and replace c.req.url with a safe
value such as new URL(c.req.url, `http://${c.req.headers.host ||
'localhost'}`).pathname or an equivalent helper that strips query and fragment,
keeping the property name consistent if other code depends on it.
- Around line 179-186: The POST fetch to posthogUrl inside
capturePosthogException currently lacks a timeout; wrap the request with an
AbortController and a short timeout (matching the backend pattern used in
dns-verification.ts/webhook.ts), start a timer that calls controller.abort()
after the timeout, pass signal: controller.signal into the fetch call that sends
JSON.stringify(body), and ensure the timer is cleared on success/failure so the
request cannot hang indefinitely.
---
Nitpick comments:
In `@supabase/functions/_backend/utils/posthog.ts`:
- Around line 96-101: The fallback branch currently discards the parsed
functionName and always sets function to fallbackFunctionName; instead, preserve
any existing parsed functionName and only use fallbackFunctionName when
functionName is empty. Update the return in the block guarded by
lastColonIndex/secondLastColonIndex to set function to functionName ||
fallbackFunctionName (or otherwise prefer functionName when present), keeping
platform and lang as-is; reference the variables lastColonIndex,
secondLastColonIndex, fallbackFunctionName, and functionName to locate and fix
the logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 88ee1f7e-2d0c-4353-9b4b-96b0356ce66d
📒 Files selected for processing (1)
supabase/functions/_backend/utils/posthog.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d97efac90
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|


Summary (AI generated)
$exceptionpayloads,$exception_list, and$exception_fingerprintMotivation (AI generated)
The codebase no longer needs a split observability setup where backend exception reporting depends on Sentry while product analytics already use PostHog. Moving fully to PostHog reduces operational overhead and aligns backend exception telemetry with the team's current analytics platform.
Business Impact (AI generated)
This removes Sentry-specific deployment and secret management, keeps backend failures visible in the PostHog error-tracking product, and simplifies ongoing maintenance for releases and production observability. That lowers tooling complexity without dropping backend exception visibility.
Test Plan (AI generated)
bunx vitest run tests/posthog.unit.test.ts tests/on-error-posthog.unit.test.ts tests/tracking.unit.test.tsbunx vitest run tests/on-error-posthog.unit.test.tsbun lint:backendbunx deno check --config supabase/functions/deno.json supabase/functions/_backend/utils/posthog.tsGenerated with AI
Summary by CodeRabbit
New Features
Tests
Chores