Skip to content

Commit 47fd67f

Browse files
committed
feat(api): add optional Sentry error tracking via SENTRY_DSN
1 parent debad74 commit 47fd67f

6 files changed

Lines changed: 391 additions & 91 deletions

File tree

.env.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,7 @@ SMTP_REQUIRE_TLS=
7373
# placeholder and apps/web/env.sh substitutes it at container start from this
7474
# env var. For local dev (vite), set VITE_TURNSTILE_SITE_KEY in apps/web/.env.
7575
#KANEO_TURNSTILE_SITE_KEY=
76+
77+
# Sentry error tracking (Optional) — errors are only reported when a DSN is set
78+
# SENTRY_DSN=
79+
# SENTRY_ENVIRONMENT=production

apps/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@oslojs/crypto": "^1.0.1",
4343
"@oslojs/encoding": "^1.1.0",
4444
"@paralleldrive/cuid2": "^3.3.0",
45+
"@sentry/node": "^10.68.0",
4546
"@valibot/to-json-schema": "^1.7.1",
4647
"bcryptjs": "^3.0.2",
4748
"better-auth": "^1.6.9",

apps/api/src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import "./instrument";
2+
13
import { dirname } from "node:path";
24
import { fileURLToPath, pathToFileURL } from "node:url";
35
import { serve } from "@hono/node-server";
46
import { createNodeWebSocket } from "@hono/node-ws";
7+
import * as Sentry from "@sentry/node";
58
import type { Session, User } from "better-auth/types";
69
import { eq, sql } from "drizzle-orm";
710
import { migrate } from "drizzle-orm/node-postgres/migrator";
@@ -148,6 +151,19 @@ function buildContentDisposition(filename: string, inline: boolean) {
148151

149152
export function createApp() {
150153
const app = new Hono<AppVariables>();
154+
155+
app.onError((err, c) => {
156+
if (err instanceof HTTPException) {
157+
// expected errors (401/404/...) are not reported; real failures are
158+
if (err.status >= 500) {
159+
Sentry.captureException(err);
160+
}
161+
return err.getResponse();
162+
}
163+
164+
Sentry.captureException(err);
165+
return c.json({ message: "Internal Server Error" }, 500);
166+
});
151167
const nodeWs = createNodeWebSocket({ app });
152168
const { upgradeWebSocket, injectWebSocket } = nodeWs;
153169
const corsOriginSource = [

apps/api/src/instrument.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from "@sentry/node";
2+
3+
if (process.env.SENTRY_DSN) {
4+
Sentry.init({
5+
dsn: process.env.SENTRY_DSN,
6+
environment:
7+
process.env.SENTRY_ENVIRONMENT ?? process.env.NODE_ENV ?? "production",
8+
sendDefaultPii: false,
9+
});
10+
}

apps/docs/docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@
170170
},
171171
"integrations": {
172172
"plausible": {
173-
"domain": "kaneo.app/docs",
173+
"domain": "kaneo.app",
174174
"server": "plausible.kaneo.app"
175175
}
176176
}

0 commit comments

Comments
 (0)