Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/webapp-sentry-fingerprint-p1001.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: improvement
---

Group Prisma P1001 ("Can't reach database server") errors into a single Sentry issue via a `beforeSend` fingerprint rule, so DB outages no longer fan out into hundreds of distinct issues that bury other alerts. Adds a small extensible rule table for future collapsing rules.
33 changes: 33 additions & 0 deletions apps/webapp/sentry.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import * as Sentry from "@sentry/remix";
import { addOtelTraceContextToEvent } from "./app/utils/sentryTraceContext.server";

// Rules for collapsing high-volume errors into a single Sentry issue.
// Without this, e.g. a DB outage produces hundreds of distinct issues —
// one per stack trace — which buries other alerts. Add a new rule here
// when you spot another error that fans out across call sites. Keep
// predicates cheap (string compare, not regex over stack traces).
const FINGERPRINT_RULES: Array<{
match: (err: { code?: unknown; errorCode?: unknown; name?: unknown }) => boolean;
fingerprint: string;
tags?: Record<string, string>;
}> = [
{
// Prisma surfaces P1001 on `code` for KnownRequestError (mid-query connection drop)
// and `errorCode` for InitializationError (client failed to connect at startup).
match: (err) => err.code === "P1001" || err.errorCode === "P1001",
fingerprint: "prisma-p1001-db-unreachable",
tags: { db_unreachable: "true" },
},
];
Comment thread
d-cs marked this conversation as resolved.

if (process.env.SENTRY_DSN) {
console.log("🔭 Initializing Sentry");

Expand Down Expand Up @@ -29,6 +48,20 @@ if (process.env.SENTRY_DSN) {
// and stay visible.
ignoreErrors: ["queryRoute() call aborted", /^ServiceValidationError(?::|$)/],
includeLocalVariables: false,

beforeSend(event, hint) {
const err = hint.originalException as
| { code?: unknown; errorCode?: unknown; name?: unknown }
| undefined;
if (!err) return event;

const rule = FINGERPRINT_RULES.find((r) => r.match(err));
if (!rule) return event;

event.fingerprint = [rule.fingerprint];
if (rule.tags) event.tags = { ...event.tags, ...rule.tags };
return event;
},
});

Sentry.addEventProcessor(addOtelTraceContextToEvent);
Expand Down