Skip to content

Commit 65ce31e

Browse files
hoangsonwwclaude
andcommitted
feat(observability): integrate Sentry error + performance monitoring (frontend + backend)
Wire Sentry into the two user-facing tiers, fully opt-in via env var so local dev and CI never phone home: - backend (Django): sentry_sdk.init() in settings.py, guarded on SENTRY_DSN. The [django] extra auto-enables request/exception capture -- no middleware edits. Tunables: SENTRY_ENVIRONMENT, SENTRY_RELEASE, SENTRY_TRACES_SAMPLE_RATE (default 0.1), SENTRY_SEND_PII (default False). Adds sentry-sdk[django]==2.66.0 to requirements.txt. - frontend (React CRA): Sentry.init() in src/index.js, guarded on REACT_APP_SENTRY_DSN, with browserTracing + replay integrations and a Sentry.ErrorBoundary fallback so render failures no longer white-screen. Adds @sentry/react. Also documents the addition: Sentry badge + Observability notes in README, ARCHITECTURE, DEPLOYMENT, and both frontend/backend READMEs; new env vars in .env.example files. Verified: manage.py check clean, 245 backend tests pass, frontend build OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent de8337a commit 65ce31e

12 files changed

Lines changed: 248 additions & 4 deletions

File tree

ARCHITECTURE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,17 @@ long-term observability target. The **current production deployment**
12931293
on Vercel + Modal + Atlas runs a simpler, free-tier-only pipeline
12941294
that backs the live `/metrics` endpoints on both services.
12951295

1296+
Alongside that `/metrics` pipeline, **Sentry** provides opt-in error
1297+
tracking and performance tracing for the two user-facing tiers — the React
1298+
frontend (`@sentry/react`, initialised in `frontend/src/index.js`) and the
1299+
Django API (`sentry-sdk[django]`, initialised in `backend/backend/settings.py`).
1300+
Both initialise only when a DSN is present (`REACT_APP_SENTRY_DSN` /
1301+
`SENTRY_DSN`), so local dev and CI stay offline; in production they stream
1302+
unhandled exceptions plus a sampled slice of traces (default 10%) to the
1303+
`unc-a4/moodify-app` project. The frontend also wraps the app in a Sentry
1304+
`ErrorBoundary` so React render failures surface a fallback instead of a
1305+
blank screen. PII (user id / IP / cookies) is **not** attached by default.
1306+
12961307
#### Pipeline
12971308

12981309
```mermaid

DEPLOYMENT.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ Required envs for the **frontend** Vercel project (CRA build-time):
6262

6363
* `REACT_APP_API_URL``https://moodify-backend-api.vercel.app`
6464
* `REACT_APP_MODAL_API_URL` → Modal service URL printed by `modal deploy`
65+
* _Optional:_ `REACT_APP_SENTRY_DSN` (+ `REACT_APP_SENTRY_ENVIRONMENT`,
66+
`REACT_APP_SENTRY_TRACES_SAMPLE_RATE`) to turn on Sentry monitoring. Leave
67+
unset to disable.
6568

6669
Required envs for the **backend** Vercel project:
6770

@@ -74,6 +77,10 @@ Required envs for the **backend** Vercel project:
7477
`WEBAUTHN_RP_NAME` (default `Moodify`), `WEBAUTHN_CHALLENGE_TTL_SECONDS`
7578
(default `300`). Defaults target `localhost` for local dev. If these don't
7679
match the domain the browser is on, passkey ceremonies fail in the browser.
80+
* **Sentry (optional):** `SENTRY_DSN` enables error + performance monitoring;
81+
leave unset to disable. Tune with `SENTRY_ENVIRONMENT`, `SENTRY_RELEASE`,
82+
`SENTRY_TRACES_SAMPLE_RATE` (default `0.1`), and `SENTRY_SEND_PII`
83+
(default `False`).
7784

7885
Required envs for the **mobile** Expo app (set via `eas env:create` or
7986
in `mobile/.env`):

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ are also used to visualize emotion trends and model performance. Users open reco
9999
<img src="https://img.shields.io/badge/Jenkins-D24939?style=for-the-badge&logo=jenkins&logoColor=white" alt="Jenkins" />
100100
<img src="https://img.shields.io/badge/GitHub_Actions-2088FF?style=for-the-badge&logo=githubactions&logoColor=white" alt="GitHub Actions" />
101101

102+
<!-- Observability / monitoring -->
103+
<img src="https://img.shields.io/badge/Sentry-362D59?style=for-the-badge&logo=sentry&logoColor=white" alt="Sentry" />
104+
102105
<!-- Hosting -->
103106
<img src="https://img.shields.io/badge/Vercel-000000?style=for-the-badge&logo=vercel&logoColor=white" alt="Vercel" />
104107
<img src="https://img.shields.io/badge/Modal-7B68EE?style=for-the-badge&logo=modal&logoColor=white" alt="Modal" />
@@ -909,6 +912,15 @@ container restarts and scale-to-zero. See
909912
and [`backend/README.md#sre-metrics`](backend/README.md#sre-metrics)
910913
for the full design (schema, resilience model, cost math).
911914

915+
Alongside the aggregated `/metrics` surface, **Sentry** provides opt-in
916+
error tracking and performance tracing for the two user-facing tiers — the
917+
React frontend (`@sentry/react`) and the Django API (`sentry-sdk[django]`).
918+
Both initialise only when a DSN is set (`REACT_APP_SENTRY_DSN` /
919+
`SENTRY_DSN`), so local dev and CI stay offline; in production they stream
920+
unhandled exceptions plus a sampled slice of traces to the
921+
[`unc-a4/moodify-app`](https://unc-a4.sentry.io/settings/projects/moodify-app/)
922+
project.
923+
912924
### **Admin Interface Endpoints**
913925

914926
| HTTP Method | Endpoint | Description |

backend/.env.example

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@ CACHE_REDIS_URL=
4545
# --- Optional: API throttling rates ---
4646
THROTTLE_ANON=60/min
4747
THROTTLE_USER=240/min
48+
49+
# --- Optional: Sentry error + performance monitoring ---
50+
# Leave SENTRY_DSN empty to disable (the SDK never initializes). Get the DSN
51+
# from the project settings at unc-a4.sentry.io/settings/projects/moodify-app.
52+
SENTRY_DSN=
53+
# Deploy stage label (defaults to production, or development when DEBUG=True).
54+
SENTRY_ENVIRONMENT=
55+
# Release/version tag for regression tracking (auto-detected from git if unset).
56+
SENTRY_RELEASE=
57+
# Fraction (0.0-1.0) of requests traced for performance. 0.1 = 10%.
58+
SENTRY_TRACES_SAMPLE_RATE=0.1
59+
# Attach user id / IP / cookies to events. Off by default for privacy.
60+
SENTRY_SEND_PII=False

backend/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ in your Vercel project's Environment Variables for production.
594594
| `METRICS_TTL_DAYS` | no | Native TTL for raw metric events. Default `30`. |
595595
| `ADMIN_METRICS_TOKEN` | no | Bearer token that unlocks `GET /api/metrics/`. Falls back to `MODAL_SERVICE_TOKEN` so a single secret unlocks both `/metrics` surfaces. |
596596
| `CACHE_REDIS_URL` | no | If set, use Redis (e.g. Upstash) instead of LocMem cache |
597+
| `SENTRY_DSN` | no | Enable Sentry error + performance monitoring. Empty ⇒ SDK never initialises (local/CI stay offline). DSN from the `unc-a4/moodify-app` project. |
598+
| `SENTRY_ENVIRONMENT` | no | Deploy-stage label on events. Default `production` (or `development` when `DEBUG=True`). |
599+
| `SENTRY_RELEASE` | no | Release/version tag for regression tracking. Auto-detected from git if unset. |
600+
| `SENTRY_TRACES_SAMPLE_RATE` | no | Fraction (0.0–1.0) of requests traced for performance. Default `0.1`. |
601+
| `SENTRY_SEND_PII` | no | Attach user id / IP / cookies to events. Default `False` (privacy-preserving). |
597602

598603
---
599604

backend/backend/settings.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,32 @@
2323
# service verifies them with the same key. Keep it in sync across both.
2424
JWT_SIGNING_KEY = config("JWT_SIGNING_KEY", default=SECRET_KEY)
2525

26+
# --- Error monitoring (Sentry) --------------------------------------------
27+
# Streams unhandled exceptions + a sampled slice of performance traces to
28+
# Sentry (project: unc-a4/moodify-app). Entirely opt-in: with no SENTRY_DSN
29+
# the SDK never initializes, so local dev and CI stay fully offline. The
30+
# [django] extra auto-wires request/exception capture -- no middleware edits.
31+
_SENTRY_DSN = config("SENTRY_DSN", default="")
32+
if _SENTRY_DSN:
33+
import sentry_sdk
34+
35+
sentry_sdk.init(
36+
dsn=_SENTRY_DSN,
37+
# Label events by deploy stage; falls back to DEBUG when unset.
38+
environment=config(
39+
"SENTRY_ENVIRONMENT",
40+
default="development" if DEBUG else "production",
41+
),
42+
# Git SHA / version tag for regression tracking (auto-detected if unset).
43+
release=config("SENTRY_RELEASE", default=None),
44+
# Fraction of requests captured as performance transactions. 10% keeps
45+
# trace volume (and quota) sane under real traffic; raise for debugging.
46+
traces_sample_rate=config("SENTRY_TRACES_SAMPLE_RATE", default=0.1, cast=float),
47+
# Do NOT attach user id / IP / cookies unless explicitly opted in --
48+
# this API handles auth material, so default to privacy-preserving.
49+
send_default_pii=config("SENTRY_SEND_PII", default=False, cast=bool),
50+
)
51+
2652
# --- MongoDB (the only datastore) -----------------------------------------
2753
# connect() is lazy -- it does not open a socket until the first query.
2854
# maxPoolSize is kept small: on a serverless host each instance keeps its

backend/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ python-dotenv==1.0.1
3434
whitenoise==6.7.0
3535
gunicorn==23.0.0
3636
tzdata==2024.2
37+
38+
# --- Error monitoring (Sentry) ---
39+
# The [django] extra auto-enables DjangoIntegration -- the only wiring is a
40+
# single sentry_sdk.init() in settings.py, which no-ops unless SENTRY_DSN is
41+
# set, so local dev and CI never phone home.
42+
sentry-sdk[django]==2.66.0

frontend/.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@ REACT_APP_API_URL=https://your-django-api.vercel.app
77

88
# Modal ML inference service (speech + facial emotion, direct upload).
99
REACT_APP_MODAL_API_URL=https://your-org--moodify-inference-inferenceservice-web.modal.run
10+
11+
# --- Optional: Sentry error + performance monitoring ---
12+
# Leave REACT_APP_SENTRY_DSN empty to disable (the SDK never initializes).
13+
# Get the DSN from unc-a4.sentry.io/settings/projects/moodify-app. Only the
14+
# public DSN belongs here -- it is safe to expose in a client build.
15+
REACT_APP_SENTRY_DSN=
16+
# Deploy stage label (defaults to NODE_ENV when unset).
17+
REACT_APP_SENTRY_ENVIRONMENT=
18+
# Fraction (0.0-1.0) of transactions traced for performance. 0.1 = 10%.
19+
REACT_APP_SENTRY_TRACES_SAMPLE_RATE=0.1

frontend/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,14 @@ sequenceDiagram
488488
Environment Variables panel (Production / Preview / Development) and
489489
redeploy - `frontend/src/config.js` reads them at build time.
490490

491+
Optionally, enable **Sentry** error + performance monitoring by also
492+
setting `REACT_APP_SENTRY_DSN` (from the `unc-a4/moodify-app` project).
493+
Leave it empty to disable — `frontend/src/index.js` only initialises the
494+
SDK when a DSN is present, so local dev and CI builds send nothing.
495+
`REACT_APP_SENTRY_ENVIRONMENT` and `REACT_APP_SENTRY_TRACES_SAMPLE_RATE`
496+
(default `0.1`) tune the stage label and trace sampling. Only the public
497+
DSN belongs in the client build.
498+
491499
### Running the Application
492500

493501
To start the development server, run the following command:

frontend/package-lock.json

Lines changed: 107 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)