feat(observability): add Sentry error monitoring (@sentry/nextjs)
Server, edge, and client instrumentation wired up via SENTRY_DSN / NEXT_PUBLIC_SENTRY_DSN. Fully inert without a DSN configured (verified with a clean local build + full test suite) — safe to ship ahead of actually having a Sentry project. Source-map upload is opt-in via SENTRY_AUTH_TOKEN (kept out of the Docker build-arg chain since build args land in image layer history; only the public DSN is a build arg).
This commit is contained in:
1 parent
f48d98cf3a
commit
f559b3d68e
8 files changed
+1976
-62
No files matched your search
@@ -61,3 +61,16 @@ REDIS_URL="redis://localhost:6379"
|
||||
# Set to "false" to disable the invite requirement after the Alpha/Beta phase.
|
||||
# Default: "true" (invite required — enforced in proxy.ts)
|
||||
INVITE_REQUIRED="true"
|
||||
|
||||
# ── Error Monitoring (Sentry) ───────────────────────────────────
|
||||
# Sentry Dashboard -> Settings -> Projects -> <project> -> Client Keys (DSN)
|
||||
# Same DSN value in both — server-side (src/instrumentation.ts) and
|
||||
# client-side (src/instrumentation-client.ts) report to the same project.
|
||||
# Leave unset to run with Sentry fully inert (no build-time requirement).
|
||||
SENTRY_DSN="https://xxxxxxxxxxxxxxxxxxxx@o0.ingest.sentry.io/0"
|
||||
NEXT_PUBLIC_SENTRY_DSN="https://xxxxxxxxxxxxxxxxxxxx@o0.ingest.sentry.io/0"
|
||||
# Optional — only needed to upload source maps for readable stack traces.
|
||||
# Sentry Dashboard -> Settings -> Auth Tokens (needs project:releases scope).
|
||||
SENTRY_ORG="your-sentry-org"
|
||||
SENTRY_PROJECT="your-sentry-project"
|
||||
SENTRY_AUTH_TOKEN=""
|
||||
@@ -21,9 +21,11 @@ COPY . .
|
||||
# All server-side secrets are injected at runtime via docker-compose env_file.
|
||||
ARG NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
ARG NEXT_PUBLIC_SUPABASE_URL
|
||||
ARG NEXT_PUBLIC_SENTRY_DSN
|
||||
|
||||
ENV NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL
|
||||
ENV NEXT_PUBLIC_SENTRY_DSN=$NEXT_PUBLIC_SENTRY_DSN
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN npx prisma generate
|
||||
|
||||
@@ -16,6 +16,7 @@ services:
|
||||
# Docker Compose reads these from docker/.env automatically.
|
||||
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY}
|
||||
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
|
||||
NEXT_PUBLIC_SENTRY_DSN: ${NEXT_PUBLIC_SENTRY_DSN}
|
||||
image: pawfeed:latest
|
||||
container_name: pawfeed
|
||||
restart: unless-stopped
|
||||
|
||||
+11
-1
@@ -1,5 +1,6 @@
|
||||
import type { NextConfig } from "next";
|
||||
import createNextIntlPlugin from "next-intl/plugin";
|
||||
import { withSentryConfig } from "@sentry/nextjs";
|
||||
|
||||
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
|
||||
|
||||
@@ -77,4 +78,13 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export default withNextIntl(nextConfig);
|
||||
export default withSentryConfig(withNextIntl(nextConfig), {
|
||||
org: process.env.SENTRY_ORG,
|
||||
project: process.env.SENTRY_PROJECT,
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
silent: true,
|
||||
// No auth token configured on this self-hosted deploy yet — skip
|
||||
// source-map upload rather than failing the Docker build.
|
||||
sourcemaps: { disable: !process.env.SENTRY_AUTH_TOKEN },
|
||||
disableLogger: true,
|
||||
});
|
||||
Generated
+1922
-60
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -19,6 +19,7 @@
|
||||
"@mux/mux-player-react": "^3.13.0",
|
||||
"@prisma/adapter-pg": "^7.8.0",
|
||||
"@prisma/client": "^7.8.0",
|
||||
"@sentry/nextjs": "^10.69.0",
|
||||
"@supabase/supabase-js": "^2.107.0",
|
||||
"@tanstack/react-query": "^5.101.0",
|
||||
"@trpc/client": "^11.17.0",
|
||||
@@ -46,7 +47,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"shadcn": "^4.10.0",
|
||||
"@types/node": "^20",
|
||||
"@types/pg": "^8.20.0",
|
||||
"@types/react": "^19",
|
||||
@@ -56,6 +56,7 @@
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.2.7",
|
||||
"jsdom": "^28.1.0",
|
||||
"shadcn": "^4.10.0",
|
||||
"tailwindcss": "^4",
|
||||
"tsx": "^4.22.4",
|
||||
"typescript": "^6.0.3",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
Sentry.init({
|
||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
tracesSampleRate: 0.1,
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
export async function register() {
|
||||
if (process.env.NEXT_RUNTIME === "nodejs") {
|
||||
Sentry.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
tracesSampleRate: 0.1,
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.NEXT_RUNTIME === "edge") {
|
||||
Sentry.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
tracesSampleRate: 0.1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const onRequestError = Sentry.captureRequestError;
|
||||
Reference in new issue
Block a user