Dashboard Get started

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 TypeUse caseStored as
GaugeCurrent value (CPU%, memory bytes)value column
Sum/CounterMonotonically increasing countsvalue column
HistogramLatency distributions, sizesp50, p99, count, sum
For histograms, Lightarch computes p50 and p99 from the OTel 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 nameTypeUnitDescription
http.server.request.durationHistogramsecondsHTTP request latency — p50/p99 visible in UI
system.cpu.utilizationGauge0–1CPU utilisation fraction
process.runtime.nodejs.memory.heap_usedGaugebytesNode.js heap memory
runtime.nodejs.heap_usedGaugebytesAlternative Node.js heap metric name
jvm.memory.usedGaugebytesJVM heap memory (Java)
system.memory.usageGaugebytesSystem 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

Node.js 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

bash
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"