Expand description
The metrics read path: match metrics, gather points, group into series.
A different shape from crate::query::search, and deliberately a separate
function rather than a mode of it. A log search filters one root table and
returns rows newest-first; a metrics query filters a descriptor table,
gathers points from four point tables that share one id space, and then
regroups them by a key that has to be stable across blocks. Folding both into
one code path would mean inventing the abstraction that both are special
cases of, which is a planner.
The grouping key is the hard part and the reason this is not trivial. Ids are rebased per block — that is what makes the attribute joins array stores — so nothing block-local can identify a series across two blocks. The key is built from values instead: the metric’s name, unit and kind, plus the merged attribute map from all four levels. That is one string built per point, which is the honest cost of a layout optimized for writing and pruning rather than for grouping.
§What V0 returns
Gauges and sums come back as their own value. Histograms, exponential
histograms and summaries come back as two derived series each, <name>.count
and <name>.sum — the same convention Prometheus uses, and the same two
numbers that answer “how often” and “how much”. Bucket and quantile maths is
not here: it is a heatmap feature, it needs the UI to exist first, and
shipping it wrong would be worse than shipping it later. Everything needed
for it is on disk already — bucket_counts, bounds_id, scale, quantile
— so this is a read-path gap, not a storage one.
Blocking: mmaps and page-faults, same as search. Callers on an async
runtime must use spawn_blocking.
Structs§
- Series 🔒
- Series
Query - A metrics query.
Enums§
- Pt 🔒
- One point. Integers stay integers: an OTLP
as_intissfixed64, and a counter past 2^53 pushed through an f64 loses its low bits — which is exactly the moment a counter is interesting. - Values 🔒
- Which columns of a point table carry chartable values, resolved once per table instead of per row.
Constants§
- COUNT 🔒
- The suffixes a histogram’s or summary’s name is derived with. Named rather than written twice, because the name filter has to accept back exactly the names the renderer hands out and two literal lists would drift apart.
- DERIVED 🔒
- DP_
TABLES 🔒 - The four point tables, and how many name suffixes each contributes.
- MAX_
EXEMPLARS 🔒 - Exemplars kept per series.
- SUM 🔒
Functions§
- bound 🔒
- Hold
outtomax_seriesentries by evicting its largest key. - collect_
attrs 🔒 - The rows one parent owns, rendered.
- collect_
block 🔒 - dedup_
last 🔒 - describe 🔒
- The descriptor’s identity as rendered JSON members, without the trailing comma. Doubles as the stable half of the series key.
- dict_
str 🔒 - exemplar_
time 🔒 - index_
by_ 🔒parent - Child rows grouped by
parent_id, indexed by it. - kind_
name 🔒 - load 🔒
- merge 🔒
- Render the union of two sorted attribute lists as a JSON object,
ownwinning on collision. A merge, not a concatenation and a re-sort:upperis already sorted and shared by every point of the metric. - names
- Every metric name present in the window, with its unit and kind.
- names_
open - As
names, but also reads the open block’s snapshot. A metric name that has only ever been written to the open block is exactly the one a dropdown must not omit — it is the new one. - own_
attrs 🔒 - series
- series_
open - As
series, but also reads the open block’s snapshot — seecrate::query::search_open, which this mirrors exactly. - u8_col 🔒
- upper_
attrs 🔒 - Attributes from the metric, resource and scope levels, sorted and deduped with the most specific level winning.
- with_
suffix 🔒 describewith the derived-series suffix folded into the name, so a.countseries reports the name a caller can query it back by.