Metrics Collector
Collects counter, histogram, and gauge metrics with arbitrary labels. Aggregates raw data into minute and hourly rollups with percentile computation. Supports Web Vitals dashboards.
| Port: 5012 | Binary: metrics-collector | Database: metrics.db |
How it works
- Receives metric data points via
POST /api/metrics - Stores raw values in SQLite
- Background thread aggregates raw data into minute buckets (count, sum, min, max, avg, p50, p95, p99)
- Every 60 aggregation cycles, computes hourly rollups from minute data
- Retention cleanup removes old data at each tier
Metric types
| Type | Description | Use case |
|---|---|---|
counter | Monotonically increasing value | Request counts, signups, events |
histogram | Distribution of values | Response times, payload sizes |
gauge | Point-in-time value | Active connections, queue depth |
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
API_KEY | Yes | – | Authentication key |
DATABASE_PATH | No | ./data/metrics.db | Path to SQLite database |
RETENTION_RAW | No | 1 | Hours to keep raw data points |
RETENTION_MINUTE | No | 24 | Hours to keep minute aggregates |
RETENTION_HOURLY | No | 30 | Days to keep hourly aggregates |
AGGREGATION_INTERVAL | No | 60 | Seconds between aggregation runs |
LOG_LEVEL | No | info | error, warn, info, debug |
API
POST /api/metrics
Submit a batch of metric data points.
Headers: X-API-Key: <api-key>, Content-Type: application/json
Body:
[
{
"name": "http_requests_total",
"type": "counter",
"value": 1,
"labels": {"method": "GET", "status": "200"},
"timestamp": "2026-01-01T12:00:00Z"
},
{
"name": "response_time_ms",
"type": "histogram",
"value": 42.5,
"labels": {"endpoint": "/api/users"}
}
]
name: metric name (max 200 chars)type:counter,histogram, orgaugevalue: numeric valuelabels: optional key-value pairs (stored as JSON)timestamp: optional ISO 8601 (defaults to server time)- Max 1000 items per batch
Response: 202 {"status":"accepted","count":2}
GET /api/metrics
Query aggregated metrics.
Query parameters:
| Param | Required | Description |
|---|---|---|
name | Yes | Metric name |
period | No | 1h, 24h, 7d, 30d (default 24h) |
resolution | No | minute, hour, auto (default auto) |
labels | No | Filter by labels: key:value,key2:value2 |
Auto resolution: minute for periods up to 24h, hour for longer periods.
Response:
{
"name": "http_requests_total",
"resolution": "minute",
"period": "24h",
"data": [
{
"bucket": "2026-01-01T12:00:00Z",
"count": 150,
"sum": 150,
"min": 1,
"max": 1,
"avg": 1,
"p50": null,
"p95": null,
"p99": null
}
]
}
Percentiles (p50, p95, p99) are only computed for histogram metrics.
GET /api/metrics/names
List all known metric names.
Response: {"metrics":[{"name":"http_requests_total","type":"counter"}]}
GET /api/dashboard
Web Vitals dashboard data. Returns ratings (good/needs-improvement/poor) and per-page breakdowns.
GET /health
Response: {"status":"ok"}
Aggregation
The background aggregation thread runs every AGGREGATION_INTERVAL seconds:
Minute aggregation:
- Groups raw data points from the previous minute by (name, labels, type)
- Computes: count, sum, min, max, avg
- For histograms: sorts values and computes p50, p95, p99 using nearest-rank method
Hourly aggregation (every 60 aggregation cycles):
- Merges minute aggregates into hourly buckets
- count = SUM(count), sum = SUM(sum), min = MIN(min), max = MAX(max)
- avg = weighted average, percentiles = AVG of minute percentiles
Database schema
metrics_raw – incoming data points:
| Column | Type | Description |
|---|---|---|
id | INTEGER | Primary key |
timestamp | DATETIME | Data point timestamp |
name | VARCHAR(200) | Metric name |
labels | TEXT | JSON-encoded labels |
value | REAL | Metric value |
type | VARCHAR(20) | counter, histogram, gauge |
metrics_aggregated – rollup data:
| Column | Type | Description |
|---|---|---|
id | INTEGER | Primary key |
bucket | DATETIME | Time bucket start |
resolution | VARCHAR(10) | minute or hour |
name | VARCHAR(200) | Metric name |
labels | TEXT | JSON-encoded labels |
count | INTEGER | Number of data points |
sum | REAL | Sum of values |
min | REAL | Minimum value |
max | REAL | Maximum value |
avg | REAL | Average value |
p50 | REAL | 50th percentile (histograms only) |
p95 | REAL | 95th percentile (histograms only) |
p99 | REAL | 99th percentile (histograms only) |
Background tasks
- Aggregation: Runs every
AGGREGATION_INTERVALseconds. Computes minute rollups. - Hourly rollup: Every 60 aggregation cycles. Computes hourly aggregates from minute data.
- Retention cleanup: Every 60 aggregation cycles. Deletes data older than configured thresholds.
Rate limits
- 200 requests/minute per IP
- 512KB max request body