Skip to content

Metrics

A metric point in Lumin has four parts:

name e.g. http.requests
type counter | gauge | histogram
labels a small map of strings
value number, plus aggregations (avg/sum/min/max/p50/p95/p99 for histograms)

Names use dotted notation by convention (http.requests, mem.used_bytes), but underscores work too — the agent doesn’t normalise.

Two ingest paths:

  1. The agent scrapes your service’s /metrics endpoint. Add lumin.metrics=true, lumin.metrics.port=…, and (recommended) lumin.metrics.framework=… labels to a container. The agent fetches Prometheus exposition every tick, maps known framework names to the canonical schema, and forwards.
  2. You POST to /v1/metrics directly. Same wire format and project scoping as logs.

The agent also emits host metrics (CPU, memory, disk, net) and container metrics (per-container resource usage) without you doing anything — those don’t need labels.

The Metrics page in the UI has KPI tiles, a latency-distribution histogram, and a top-routes table. All of these are wired to three specific metric names. If your service emits these, the panels light up; if it doesn’t, you’ll have to build custom charts.

Metric Type Labels Notes
http.requests counter {method, route, status_class} status_class ∈ {2xx, 3xx, 4xx, 5xx}.
http.latency_ms histogram {method, route} Buckets [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000] ms work for typical Go/Python/Node services.
http.errors counter {method, route, status} Increment only on status >= 500. Raw 3-digit code; low cardinality in practice.

When lumin.metrics.framework is set on a container, the agent rewrites the framework’s underlying metric names to these canonical names. See the stack guides for the exact mapping per framework.

The single most important number in metrics-land is cardinality: the count of distinct label-value combinations. Cardinality drives storage cost and query latency. The rules of thumb:

  • Use templated routes, not expanded paths. /projects/:id is one route. /projects/1, /projects/2, … are N paths sharing one route. If you let expanded paths leak into the route label, the cardinality of http.requests grows linearly with your data.
  • status_class over status for counter labels. 4 values instead of ~70.
  • Don’t put user IDs, request IDs, trace IDs, or session IDs in labels. Those go on log rows, where the storage model handles high cardinality. Putting them on metric labels is the classic way to make a monitoring stack expensive.

If you find yourself needing to slice metrics by something user-shaped, the answer is usually “log this event” or “track this as a browser event”, not “add a label”.

Use a histogram when you care about distribution (p50, p95, p99), which is almost always what you want for latency, payload sizes, or any “how big does this thing get” question. Use a counter when you only care about count over time, and use a gauge when the underlying quantity is point-in-time (memory used, queue depth, …).

The default histogram buckets in Lumin’s stack guides cover the typical “1 ms to 5 seconds” range for HTTP latency. If your service is consistently faster or slower, override the buckets — the goal is to have at least three or four buckets straddle your service’s actual latency distribution so percentile estimates stay accurate.

Lumin computes avg, sum, min, max, and (for histograms) p50/p95/p99 at query time, over the window you pick in the UI.

Lumin does not downsample. It keeps every point at full resolution until the point passes your retention horizon, and then deletes it. A 30-day chart has the same resolution as a 1-hour chart. See Retention.

The agent pulls from /metrics endpoints (Prometheus model). If you’d rather push, the POST /v1/metrics endpoint accepts a JSON batch of points. Pulling is recommended for services that already expose Prometheus exposition; pushing is for cron jobs and short-lived processes that can’t host an HTTP endpoint long enough for a scrape to happen.