Observability
Usage Metrics
Usage metrics are how raw request_logs rows become the numbers on a dashboard. Vectoralix maintains three rollup tables — hourly, daily, monthly — populated by background jobs on a fixed schedule. Sub-hour windows read live from request_logs; longer windows read from the rollups. This page is the dashboard reader's mental model for that pipeline.
Why rollups exist
Scanning thirty days of raw request rows on every dashboard load does not scale. Rolling totals into bucketed summaries lets a "last 30 days" query return in constant time regardless of how busy your server has been. Rollups also outlive the raw rows: request_logs prune at day 30, but the hourly, daily, and monthly buckets are kept indefinitely, so historical charts keep working forever.
The three grains
| Grain | Bucket | Produced (UTC) |
|---|---|---|
| Hourly | One row per hour | 5 minutes past each hour, rolling up the previous full hour |
| Daily | One row per day | 00:15, rolling up the previous full day |
| Monthly | One row per calendar month | 00:30 on the 1st, rolling up the previous full month |
What gets counted in each bucket
Each bucket is keyed by (mcp_server_id, organization_id, tool_name, time-bucket) and stores total requests, error count, and average duration for that grouping. A synthetic "__total__" row is emitted per (mcp_server_id, time-bucket) so dashboards can ask "all requests this hour" without summing every per-tool row.
- Requests — every row in request_logs counts, regardless of HTTP status.
- Errors — rows with a non-2xx status, including 401, 404, 429, and 5xx.
- Average duration — averaged across the bucket, including outbound HTTP time for API URL tools.
- tool_name — null tool names from early-failure rows are bucketed under "__total__" automatically.
Freshness — hybrid live/rollup reads
The dashboard does not read a single source for every widget. It picks the source automatically based on the window the widget is asking about: short windows read live from request_logs, longer windows read from the matching rollup table.
| Window | Source | Lag |
|---|---|---|
| ≤ 1 hour | request_logs (live) | Second-fresh |
| ≤ 24 hours | request_metrics_hourly | Up to ~5 minutes |
| ≤ 30 days | request_metrics_daily | Up to ~24 hours plus 15 minutes |
| ≤ 12 months | request_metrics_monthly | Up to ~1 month plus 30 minutes |
A widget that asks for "last hour" is therefore always live. A widget that asks for "last 24 hours" can be up to a rollup-cycle behind the wall clock. The dashboard does not warn about this lag because it is bounded and small relative to the window.
A worked example
A request lands at 14:37:02 UTC. It writes a row to request_logs immediately. It is visible to a "last hour" widget within seconds. It joins the 14:00–15:00 hourly bucket at 15:05 UTC, the 2026-04-26 daily bucket at the next 00:15 UTC tick, and the April 2026 monthly bucket at 00:30 UTC on May 1st. Each later grain is computed from raw rows or earlier rollups, never from out-of-band sources.
Timezones
Bucket keys are stored in UTC. The dashboard converts to the viewer's local time at render. Two users in different timezones looking at the same organization see the same numbers, labeled for their respective zones. Reports that cross local midnight may straddle two daily buckets — read those edges from the dashboard rather than reasoning about UTC ranges by hand.
Metrics vs rate limits
Rate-limit enforcement happens upstream of observability. A request that is rejected with a 429 still produces a request_logs row and still counts toward the rolled-up totals. The enforcement decision is made by the MCP handler before tool dispatch — the rollup pipeline is downstream of that decision and only records what happened.
Retention difference
- Raw request_logs — pruned at 30 days; configurable down to a 7-day floor.
- Rollups — kept indefinitely; historical charts beyond 30 days work because the daily and monthly tables are still there.
Programmatic access (roadmap)
A public /api/v1/metrics endpoint that lets organizations pull rolled-up numbers programmatically is on the roadmap, not shipped today. For now, rollups are dashboard-only — there is no documented external API for the rollup tables.
Cross-link: Plan-tier request allowances live on the Pricing page; rate-limit headers and 429 behavior live in the MCP Deployment group under Rate Limits. This page deliberately does not duplicate those numbers.