Metrics
OpenTremor Core exposes a /metrics endpoint in Prometheus format — no separate installation, no dependency on the monitoring pack.
Metrics endpoint
Section titled “Metrics endpoint”When prometheus-client is installed (included by default), the server exposes:
GET /metrics — Prometheus scrape endpoint (no auth required)The endpoint is served by prometheus_client’s own ASGI app and is excluded from span recording. Auth is intentionally not required so Prometheus can scrape without credentials.
Metric catalogue
Section titled “Metric catalogue”Every metric below carries an org_id label, letting you slice or filter any panel/query down to one tenant — see Organization filtering.
HTTP metrics (auto-instrumented)
Section titled “HTTP metrics (auto-instrumented)”| Metric | Type | Labels | Description |
|---|---|---|---|
http_request_duration_seconds | Histogram | handler, method, status, org_id | Request latency — use for rate, p95, p99 |
Domain metrics
Section titled “Domain metrics”| Metric | Type | Labels | Description |
|---|---|---|---|
mcp_ingest_total | Counter | analyzer, org_id | Plan ingest calls |
mcp_ingested_resources_total | Counter | analyzer, org_id | Resources parsed and stored |
mcp_analysis_total | Counter | resource_type, org_id | Analysis submissions (PUT /resource/{hash}/analysis) |
mcp_findings_total | Counter | resource_type, severity, org_id | Individual findings — severity is CRITICAL, HIGH, MEDIUM, LOW, or INFO |
mcp_llm_analysis_duration_seconds | Histogram | resource_type, org_id | LLM round-trip latency: time from GET /{ns}/resource/next to PUT /resource/{hash}/analysis |
mcp_analysis_total/mcp_findings_total increment identically regardless of how the analysis was produced — client-led PUT, server-side POST .../analyze, or a GitHub-webhook-triggered run — since all three funnel through the same analysis_service.record_analysis(). Billing (usage_events/LLM token cost) and findings-triage state changes are not exposed as Prometheus metrics — query them via GET /orgs/{org_id}/usage and GET /findings/summary instead.
Organization filtering
Section titled “Organization filtering”org_id is resolved from the same request-scoped context var the telemetry span system already uses (controllers/observability/telemetry.py’s get_org_id()/set_org_id()) — no separate plumbing per metric. A request that never resolves an org (health checks, the metrics scrape itself, public report links, the GitHub webhook, SSO callbacks before login) carries org_id="_none" rather than an empty label value, so it’s always an explicit, queryable string, never blank.
# Request rate for one org onlysum(rate(http_request_duration_seconds_count{org_id="7c3c6e2e-..."}[5m]))
# Findings rate broken out per orgsum(rate(mcp_findings_total[5m])) by (org_id, severity)Scraping it yourself
Section titled “Scraping it yourself”Point any Prometheus instance at the server:
scrape_configs: - job_name: opentremor-core static_configs: - targets: - <host>:8000 metrics_path: /metricsA pre-built Grafana dashboard covering these metrics (HTTP traffic, analysis pipeline, findings by severity) ships as part of the separate OpenTremor Monitoring repo, not this repo.