Monitoring and metrics
Monitoring
For production monitoring:
- Liveness: use
GET /api/live— a failure means the app process is stuck and should be restarted. - Readiness: use
GET /api/ready— a failure means the database is unreachable or the connection pool is exhausted. - Details: admin users can check
GET /api/health/detailsfor an overview of database stats and the next scheduled ingest. - Source health: check
GET /api/sources/healthafter an ingest run to see which sources failed.
Prometheus Metrics
Set METRICS_ENABLED=true to expose a GET /metrics endpoint in Prometheus
exposition format. It's off by default and unauthenticated when on — treat it
like any other internal-only endpoint and don't expose it directly to the
public internet (put it behind your reverse proxy/network policy, or scrape
it from inside your cluster/VPC).
Metrics exposed:
news_dashboard_http_requests_total{method,path,status}— request counts, labeled by route template (e.g./api/articles/{article_id}), never the raw URL.news_dashboard_http_request_duration_seconds{method,path}— HTTP request latency histogram (exposed as_bucket,_sum, and_countseries), labeled by route template, never the raw URL.news_dashboard_ingest_runs_total{status}— ingest run outcomes (success/failure).news_dashboard_ingest_articles_new_total— new articles discovered across all ingest runs.news_dashboard_source_health_checks_total{status}— per-source fetch outcomes (ok/error) during ingest. No source identity is included in labels, since private-feed names/slugs are user-defined.news_dashboard_scheduler_job_runs_total{job_name,status}— background job outcomes (digest,briefing,recommendations,analytics_retention,per_user_briefings).
No article content, URLs, emails, or other PII ever appear in metric labels.
Example scrape config:
# prometheus.yml
scrape_configs:
- job_name: news-dashboard
metrics_path: /metrics
static_configs:
- targets: ['news-dashboard:8080']
Error Tracking
Optional, opt-in error tracking against a Sentry or GlitchTip-compatible DSN — pick a self-hosted GlitchTip instance to keep everything in-house, or a Sentry SaaS project if you prefer.
SENTRY_DSNenables backend exception capture. Unset (default): no SDK initializes and no network calls are made.SENTRY_DSN_FRONTENDenables frontend error capture. It's served to the SPA via the publicGET /api/configendpoint — this is safe because a Sentry DSN only lets a client send events, not read any data.
Both are off independently, so you can enable backend-only, frontend-only,
or both. PII is scrubbed before events are sent: send_default_pii is
disabled on both SDKs, and the backend additionally strips cookies and
Authorization/Cookie headers via a before_send hook.