Skip to content

feat(layer-4): Prometheus metrics + provisioned Grafana dashboard - #4

Merged
Mhemd139 merged 1 commit into
mainfrom
feat/layer4-observability
Jul 2, 2026
Merged

feat(layer-4): Prometheus metrics + provisioned Grafana dashboard#4
Mhemd139 merged 1 commit into
mainfrom
feat/layer4-observability

Conversation

@Mhemd139

@Mhemd139 Mhemd139 commented Jul 2, 2026

Copy link
Copy Markdown
Owner

@

What

Layer 4 of the roadmap: observability for the proxy.

  • GET /covenant/metrics — Prometheus text exposition: covenant_calls_total{tool,outcome} (ok/error/blocked), covenant_call_latency_seconds{tool} (forwarded calls only — blocked calls never reach upstream), covenant_drift_total{severity}, covenant_quarantined_tools gauge (synced on refresh + in-band detection).
  • Provisioned Grafana dashboarddocker compose up -d prometheus grafana gives calls-by-outcome, p95 latency, a quarantine stat that flips green→red within one scrape of a drift, and drift events. Dashboard + datasource fully provisioned, zero clicks.

Named decisions (Layer 4 spec)

  • One CollectorRegistry per app — the global registry collides when tests create several proxy apps in one process.
  • prometheus-client rides the [proxy] extra — metrics are meaningless without the proxy; core CLI stays dependency-light.
  • Endpoint is /covenant/metrics, not /metrics — everything Covenant owns lives under /covenant/*; the proxy stays transparent everywhere else.
  • Metrics are in-process, not store-backed — Prometheus handles restarts (rate() is reset-aware); the Layer 2 store stays the durable record. No double-write.
  • OTel spans deferred, honestly — heavy dependency tree, and every demo signal is a metric, not a trace. Revisit with a real multi-hop fleet.

Verified

  • 116 tests (5 new: ok/error/blocked counters, latency histogram, drift+gauge on refresh, registry isolation between apps), ruff + strict mypy clean
  • docker compose config -q valid
  • Not run here: the live Prometheus/Grafana stack (needs the compose stack up + real traffic) — the endpoint itself is covered by TestClient e2e

🤖 Generated with Claude Code
@

Summary by CodeRabbit

  • New Features

    • Added a new metrics endpoint to expose proxy activity in Prometheus format.
    • Introduced a Grafana dashboard and local observability setup for viewing calls, latency, quarantine status, and drift events.
    • Updated documentation to show how to access the new observability views.
  • Bug Fixes

    • Metrics are now tracked per app instance, avoiding conflicts when multiple proxy apps run in the same process.
    • Quarantine and drift updates now stay visible in the exported metrics.

The proxy now exposes GET /covenant/metrics (text exposition format):
- covenant_calls_total{tool,outcome} - ok / error / blocked
- covenant_call_latency_seconds{tool} - forwarded calls only
- covenant_drift_total{severity} - per breaking tool on refresh
- covenant_quarantined_tools - gauge, synced on refresh and in-band detection

One CollectorRegistry per app (the global registry would collide across
create_app calls in tests). prometheus-client rides the [proxy] extra.
Metric writes are in-process and non-throwing - never on the store path.

docker compose up -d prometheus grafana provisions a dashboard: calls by
outcome, p95 latency, quarantine stat (green 0 / red >=1), drift events.

OTel spans deferred (heavy dep tree, no trace consumer yet) - stated in the
Layer 4 spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b54ea801-15e6-468f-bd93-151d675dcb88

📥 Commits

Reviewing files that changed from the base of the PR and between 88b60d6 and fff5cf9.

📒 Files selected for processing (12)
  • CLAUDE.md
  • README.md
  • covenant/proxy/metrics.py
  • covenant/proxy/server.py
  • deploy/grafana/dashboards/covenant.json
  • deploy/grafana/provisioning/dashboards/provider.yml
  • deploy/grafana/provisioning/datasources/prometheus.yml
  • deploy/prometheus.yml
  • docker-compose.yml
  • docs/superpowers/specs/2026-07-03-covenant-layer4-observability-design.md
  • pyproject.toml
  • tests/test_metrics.py

📝 Walkthrough

Walkthrough

This PR adds Layer 4 observability to Covenant via a Prometheus Metrics class integrated into the proxy server, exposing a GET /covenant/metrics endpoint tracking call outcomes, latency, drift events, and quarantined tools. It adds Grafana dashboard/datasource provisioning, Docker Compose services, dependency updates, tests, and documentation.

Changes

Layer 4 Observability

Layer / File(s) Summary
Metrics module
covenant/proxy/metrics.py
New Metrics class with a per-instance CollectorRegistry, registered counter/histogram/gauge metrics, record_call(), and render().
Proxy server integration
covenant/proxy/server.py
Initializes app.state.metrics, records call outcomes (ok/error/blocked) and quarantine gauge during /mcp handling, updates drift metrics in /covenant/refresh, and adds GET /covenant/metrics.
Metrics test suite
tests/test_metrics.py
Adds async tests covering call outcomes, quarantine blocking, drift/quarantine gauge updates, and registry isolation across app instances.
Prometheus/Grafana provisioning & Compose wiring
deploy/prometheus.yml, deploy/grafana/provisioning/*, deploy/grafana/dashboards/covenant.json, docker-compose.yml, pyproject.toml
Adds Prometheus scrape config, Grafana datasource/dashboard provisioning, a dashboard JSON, new Compose services for prometheus/grafana, and the prometheus-client dependency.
Documentation updates
CLAUDE.md, README.md, docs/superpowers/specs/2026-07-03-covenant-layer4-observability-design.md
Updates architecture tables and adds the Layer 4 observability design spec.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ProxyServer
  participant Metrics
  participant Upstream

  Client->>ProxyServer: POST /mcp tools/call
  ProxyServer->>ProxyServer: check quarantine
  alt tool quarantined
    ProxyServer->>Metrics: record_call(tool, "blocked")
    ProxyServer-->>Client: error response
  else tool allowed
    ProxyServer->>Upstream: forward call
    Upstream-->>ProxyServer: JSON-RPC response
    ProxyServer->>Metrics: record_call(tool, outcome, latency_s)
    ProxyServer-->>Client: response
  end
  Client->>ProxyServer: GET /covenant/metrics
  ProxyServer->>Metrics: render()
  Metrics-->>ProxyServer: Prometheus text
  ProxyServer-->>Client: metrics payload
Loading

Possibly related PRs

  • Mhemd139/Covenant#1: The proxy's /mcp and /covenant/refresh handling in server.py introduced in this PR builds directly on the create_app/call-handling paths added there.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/layer4-observability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Mhemd139
Mhemd139 merged commit 4da550a into main Jul 2, 2026
5 checks passed
@Mhemd139

Mhemd139 commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Mhemd139 added a commit that referenced this pull request Jul 4, 2026
feat(layer-4): Prometheus metrics + provisioned Grafana dashboard
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant