Metrics
Lightarch ingests OpenTelemetry metrics via /v1/metrics. Histograms have p50/p99 computed at ingest time — no expensive percentile queries at read time. Raw metric samples are kept for 7 days; daily aggregates survive indefinitely in usage_daily.
Screenshot needed
Metrics page: 4 charts in 2x2 grid. Top-left: Request Rate line chart showing req/s over time for api-gateway. Top-right: Latency p50/p99 chart with two lines (solid=p50, dashed=p99) in ms. Bottom-left: Heap Memory area chart in MB. Bottom-right: CPU Utilization line chart 0-100% with red 80% reference line.
Supported metric types
| OTel Type | Use case | Stored as |
|---|---|---|
| Gauge | Current value (CPU%, memory bytes) | value column |
| Sum/Counter | Monotonically increasing counts | value column |
| Histogram | Latency distributions, sizes | p50, p99, count, sum |
explicitBounds and bucketCounts at ingest time. This means percentile queries are instant — no raw bucket data stored in D1.Standard metrics (auto-collected)
These are automatically emitted by OTel auto-instrumentation:
| Metric name | Type | Unit | Description |
|---|---|---|---|
| http.server.request.duration | Histogram | seconds | HTTP request latency — p50/p99 visible in UI |
| system.cpu.utilization | Gauge | 0–1 | CPU utilisation fraction |
| process.runtime.nodejs.memory.heap_used | Gauge | bytes | Node.js heap memory |
| runtime.nodejs.heap_used | Gauge | bytes | Alternative Node.js heap metric name |
| jvm.memory.used | Gauge | bytes | JVM heap memory (Java) |
| system.memory.usage | Gauge | bytes | System memory usage |
Filtering metrics
At the top of the Metrics page, use the time preset buttons (5m / 15m / 1h / 6h / 24h / 3d / 7d) and service chip filters to focus on specific services.
Screenshot needed
Metrics page top controls: time preset pills with '1h' selected (cyan), service chip buttons showing 'api-gateway' (selected, cyan) and 'payment-service' (unselected). Received Metrics table at the bottom showing metric names, types, and which services emit each.
Custom metrics
import { metrics } from '@opentelemetry/api';
const meter = metrics.getMeter('my-service');
// Counter — how many orders processed
const ordersCounter = meter.createCounter('orders.processed', {
description: 'Number of orders processed',
});
// Histogram — payment processing time
const paymentDuration = meter.createHistogram('payment.duration', {
description: 'Payment processing duration',
unit: 'ms',
});
// Gauge — queue depth
const queueDepth = meter.createObservableGauge('queue.depth', {
description: 'Current queue depth',
});
queueDepth.addCallback(obs => {
obs.observe(getQueueDepth());
});
// Usage
ordersCounter.add(1, { 'order.type': 'subscription' });
paymentDuration.record(342, { 'payment.provider': 'stripe' });Verify metrics are arriving
la query "SELECT metric_name, service, ROUND(p99, 1) as p99_ms, ROUND(value, 3) as value FROM metrics_samples ORDER BY timestamp DESC LIMIT 10"