Skip to content

Add per-server metrics and Prometheus endpoint for monitoring - #5

Merged
Deep-Axe merged 4 commits into
mainfrom
fix/connection-history-names
Oct 26, 2026
Merged

Deep-Axe merged 4 commits into
mainfrom
fix/connection-history-names

Conversation

@Deep-Axe

@Deep-Axe Deep-Axe commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Implements stand-out item #8 Observability by adding per-server tool-call metrics, an in-cluster Prometheus /metrics endpoint, dashboard metrics on each connection card, and server-slug retention in connection history.

Changes

  • Prometheus metrics endpoint (services/gateway/src/metrics.ts, services/gateway/src/main.ts, charts/storelink/):
    • Exposes /metrics on a dedicated in-cluster port (gateway.metrics.port, default 9464) with prometheus.io/scrape pod annotations and no public Ingress route.
    • Exports per-server call counters by outcome (storelink_tool_calls_total), a cumulative latency histogram from 5 ms to 15 s (storelink_tool_call_duration_seconds), and upstream connectivity/status/last-failure gauges (storelink_upstream_up, storelink_upstream_status, storelink_upstream_last_failure_timestamp_seconds).
    • Hydrates lastSuccessAt, lastFailureAt, and lastError from PostgreSQL on gateway startup so failure timestamps survive restarts.
  • Dashboard & JSON metrics (services/gateway/src/dashboard-api.ts, services/gateway/src/registry.ts, apps/dashboard/src/main.tsx):
    • Aggregates 24-hour call volume, error rate, and average/p95 latency per server from audit_calls for administrators on the Connections cards and via GET /api/metrics?hours=<1-168>.
    • Attributes denied tool calls (tool_unavailable, key_revoked, session_owner_mismatch) to the requested server namespace so per-server denied counters and audit rows identify the target server.
  • Connection history names (services/gateway/migrations/0005_event_slugs.sql, services/gateway/src/registry.ts, apps/dashboard/src/main.tsx):
    • Stores the server slug on upstream_events, records a Removed event when a server is deleted, and backfills existing rows so connection history keeps readable names after a server is removed.
  • Documentation (README.md, docs/system-design.md, docs/verification.md):
    • Documents the metrics endpoint, PromQL error-rate query, Helm values (gateway.metrics.enabled, gateway.metrics.port), and updates stand-out item #8 Observability to Implemented.

Validation

  • Automated checks:
    • npm run typecheck
    • npm test (41 / 41 tests passing, including tests/metrics.test.ts and denial server-attribution assertions in tests/mcp-notifications.test.ts)
    • npm run build:dashboard
    • npm run format:check
    • helm lint charts/storelink -f charts/storelink/values-local.yaml & values-prod.yaml
  • Live cluster checks (storelink k3d cluster):
    • Verified /metrics on port 9464 inside the cluster exports counters, histogram buckets, and upstream gauges while http://dashboard.storelink.localhost/metrics via public Ingress returns 404.
    • Verified GET /api/metrics and GET /api/servers return 24h call counts, error rates, and avg/p95 latency to admins and 403 to members.
    • Verified HTTP key_revoked and tool_unavailable calls record the target server_id in audit_calls and increment outcome="denied" in /metrics.
    • Verified node scripts/smoke-cluster.ts and node scripts/smoke-dashboard.ts pass against the deployed cluster.

Derive tool-call metrics from the audit log with one aggregation query shared
by PostgreSQL and SQLite: outcome counts per upstream and a fixed latency
histogram from 5 ms to 15 s.

The gateway serves Prometheus metrics on a separate in-cluster port
(gateway.metrics.port, default 9464) that the Ingress does not route:
call counters by outcome, a latency histogram, and upstream up, status and
last-failure gauges. The pod carries prometheus.io scrape annotations.

Administrators see each server's calls, error rate and average and p95
latency for the last 24 hours on its Connections card and at
GET /api/metrics?hours=<1-168>. Members do not receive team-wide metrics.
Store the slug on each upstream event, record a Removed event when a
server is deleted, and backfill existing events from the server list or
the audit log. The dashboard falls back to the stored slug instead of the
raw server ID.
…restarts

Denied calls (disabled server, revoked key) now record the server whose
namespace was requested, so per-server metrics and the activity log count
them. The registry seeds last success, failure and error from PostgreSQL
when it registers an upstream, so the last-failure gauge survives a
gateway restart.
Revoked-key and session-owner-mismatch denials recorded by the MCP
handler now store the server whose namespace was requested, matching the
denials recorded inside gateway.call().
@Deep-Axe
Deep-Axe merged commit 1d7e59c into main Oct 26, 2026
2 checks passed
@Deep-Axe
Deep-Axe deleted the fix/connection-history-names branch October 26, 2026 13:51
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