use std::sync::OnceLock;
use prometheus::{
HistogramVec, IntCounter, IntCounterVec, IntGauge, histogram_opts, register_histogram_vec,
register_int_counter, register_int_counter_vec, register_int_gauge,
};
const SCOPE_LABELS: [&str; 4] = ["fleet", "grant", "persona", "conversations"];
fn source_events() -> &'static HistogramVec {
static V: OnceLock<HistogramVec> = OnceLock::new();
V.get_or_init(|| {
register_histogram_vec!(
histogram_opts!(
"polychrome_query_source_events",
"Total events replayed for one query, across every scoped partition, by scope.",
vec![
100.0,
1_000.0,
10_000.0,
50_000.0,
100_000.0,
250_000.0,
500_000.0,
1_000_000.0,
2_000_000.0,
5_000_000.0,
]
),
&["scope"]
)
.expect("register polychrome_query_source_events")
})
}
fn replayed_bytes() -> &'static HistogramVec {
static V: OnceLock<HistogramVec> = OnceLock::new();
V.get_or_init(|| {
register_histogram_vec!(
histogram_opts!(
"polychrome_query_replayed_bytes",
"Total replayed event payload bytes for one query, across every scoped \
partition, by scope.",
vec![
1_024.0,
16_384.0,
131_072.0,
1_048_576.0,
16_777_216.0,
134_217_728.0,
536_870_912.0,
1_073_741_824.0,
]
),
&["scope"]
)
.expect("register polychrome_query_replayed_bytes")
})
}
fn cached_scan_events() -> &'static HistogramVec {
static V: OnceLock<HistogramVec> = OnceLock::new();
V.get_or_init(|| {
register_histogram_vec!(
histogram_opts!(
"polychrome_query_cached_scan_events",
"Total effective event volume one query hands to DataFusion — cached rows plus \
any freshly-replayed tail, summed across every scoped partition, by scope.",
vec![
100.0,
1_000.0,
10_000.0,
50_000.0,
100_000.0,
250_000.0,
500_000.0,
1_000_000.0,
2_000_000.0,
5_000_000.0,
]
),
&["scope"]
)
.expect("register polychrome_query_cached_scan_events")
})
}
fn cached_scan_bytes() -> &'static HistogramVec {
static V: OnceLock<HistogramVec> = OnceLock::new();
V.get_or_init(|| {
register_histogram_vec!(
histogram_opts!(
"polychrome_query_cached_scan_bytes",
"Total Arrow array memory one query hands to DataFusion — cached rows plus any \
freshly-replayed tail, summed across every scoped partition, by scope.",
vec![
1_024.0,
16_384.0,
131_072.0,
1_048_576.0,
16_777_216.0,
134_217_728.0,
536_870_912.0,
1_073_741_824.0,
]
),
&["scope"]
)
.expect("register polychrome_query_cached_scan_bytes")
})
}
fn source_budget_exceeded_total() -> &'static IntCounterVec {
static V: OnceLock<IntCounterVec> = OnceLock::new();
V.get_or_init(|| {
register_int_counter_vec!(
"polychrome_query_source_budget_exceeded_total",
"Count of queries refused for exceeding the pre-execution source-event budget, by \
scope.",
&["scope"]
)
.expect("register polychrome_query_source_budget_exceeded_total")
})
}
pub(crate) fn record_query_observed(scope: &str, events: usize, bytes: u64) {
#[allow(
clippy::cast_precision_loss,
reason = "a metrics observation, not an exact accounting value"
)]
source_events()
.with_label_values(&[scope])
.observe(events as f64);
record_query_replayed_bytes(scope, bytes);
}
pub(crate) fn record_query_replayed_bytes(scope: &str, bytes: u64) {
#[allow(
clippy::cast_precision_loss,
reason = "a metrics observation, not an exact accounting value"
)]
replayed_bytes()
.with_label_values(&[scope])
.observe(bytes as f64);
}
pub(crate) fn record_source_budget_exceeded(scope: &str) {
source_budget_exceeded_total()
.with_label_values(&[scope])
.inc();
}
pub(crate) fn record_cached_scan_volume(scope: &str, events: usize, bytes: u64) {
#[allow(
clippy::cast_precision_loss,
reason = "a metrics observation, not an exact accounting value"
)]
cached_scan_events()
.with_label_values(&[scope])
.observe(events as f64);
#[allow(
clippy::cast_precision_loss,
reason = "a metrics observation, not an exact accounting value"
)]
cached_scan_bytes()
.with_label_values(&[scope])
.observe(bytes as f64);
}
fn cache_hit_total() -> &'static IntCounter {
static V: OnceLock<IntCounter> = OnceLock::new();
V.get_or_init(|| {
register_int_counter!(
"polychrome_query_cache_hit_total",
"Count of decode-cache lookups served entirely from the cache, with no replay or \
decode."
)
.expect("register polychrome_query_cache_hit_total")
})
}
fn cache_tail_total() -> &'static IntCounter {
static V: OnceLock<IntCounter> = OnceLock::new();
V.get_or_init(|| {
register_int_counter!(
"polychrome_query_cache_tail_total",
"Count of decode-cache lookups that replayed and decoded only a tail onto an \
already-cached partition."
)
.expect("register polychrome_query_cache_tail_total")
})
}
fn cache_full_rebuild_total() -> &'static IntCounter {
static V: OnceLock<IntCounter> = OnceLock::new();
V.get_or_init(|| {
register_int_counter!(
"polychrome_query_cache_full_rebuild_total",
"Count of decode-cache lookups that forced a full replay and decode: no prior entry, \
or a mutation-epoch mismatch."
)
.expect("register polychrome_query_cache_full_rebuild_total")
})
}
fn cache_eviction_total() -> &'static IntCounter {
static V: OnceLock<IntCounter> = OnceLock::new();
V.get_or_init(|| {
register_int_counter!(
"polychrome_query_cache_eviction_total",
"Count of partitions the decode cache evicted, by LRU-over-budget or proactive \
hygiene on a partition mutation."
)
.expect("register polychrome_query_cache_eviction_total")
})
}
fn cached_volume_budget_exceeded_total() -> &'static IntCounterVec {
static V: OnceLock<IntCounterVec> = OnceLock::new();
V.get_or_init(|| {
register_int_counter_vec!(
"polychrome_query_cached_volume_budget_exceeded_total",
"Count of queries refused for exceeding the cached-scan volume budget, by scope.",
&["scope"]
)
.expect("register polychrome_query_cached_volume_budget_exceeded_total")
})
}
const SEARCH_UNAVAILABLE_REASONS: [&str; 6] = [
"replay_budget_exceeded",
"record_too_large",
"replay_failed",
"source_unreadable",
"source_empty",
"store_failed",
];
const SEARCH_REBUILD_CAUSES: [&str; 2] = ["excision", "unavailable_recovery"];
fn search_index_unavailable_total() -> &'static IntCounterVec {
static V: OnceLock<IntCounterVec> = OnceLock::new();
V.get_or_init(|| {
register_int_counter_vec!(
"polychrome_search_index_unavailable_total",
"Count of conversations the search index left unsearchable, by reason.",
&["reason"]
)
.expect("register polychrome_search_index_unavailable_total")
})
}
fn search_index_rebuild_total() -> &'static IntCounterVec {
static V: OnceLock<IntCounterVec> = OnceLock::new();
V.get_or_init(|| {
register_int_counter_vec!(
"polychrome_search_index_rebuild_total",
"Count of search-index rebuilds a forward pass escalated to, by cause.",
&["cause"]
)
.expect("register polychrome_search_index_rebuild_total")
})
}
fn search_index_barrier_held_total() -> &'static IntCounter {
static V: OnceLock<IntCounter> = OnceLock::new();
V.get_or_init(|| {
register_int_counter!(
"polychrome_search_index_barrier_held_total",
"Count of search-index passes pinned behind a turn that opened and never completed."
)
.expect("register polychrome_search_index_barrier_held_total")
})
}
fn search_index_reconcile_total() -> &'static IntCounterVec {
static V: OnceLock<IntCounterVec> = OnceLock::new();
V.get_or_init(|| {
register_int_counter_vec!(
"polychrome_search_index_reconcile_total",
"Count of search-index reconcile sweeps, by whether the sweep cleared the degraded \
flag.",
&["cleared"]
)
.expect("register polychrome_search_index_reconcile_total")
})
}
fn search_index_reconcile_refused() -> &'static IntGauge {
static V: OnceLock<IntGauge> = OnceLock::new();
V.get_or_init(|| {
register_int_gauge!(
"polychrome_search_index_reconcile_refused",
"Conversations the last search-index reconcile sweep left unsearchable."
)
.expect("register polychrome_search_index_reconcile_refused")
})
}
fn search_index_pending_partitions() -> &'static IntGauge {
static V: OnceLock<IntGauge> = OnceLock::new();
V.get_or_init(|| {
register_int_gauge!(
"polychrome_search_index_pending_partitions",
"Partitions the search index's dirty set still owes work on."
)
.expect("register polychrome_search_index_pending_partitions")
})
}
fn search_index_degraded() -> &'static IntGauge {
static V: OnceLock<IntGauge> = OnceLock::new();
V.get_or_init(|| {
register_int_gauge!(
"polychrome_search_index_degraded",
"1 while the search index is degraded and refuses every search, 0 otherwise."
)
.expect("register polychrome_search_index_degraded")
})
}
pub(crate) fn record_search_index_unavailable(reason: &str) {
search_index_unavailable_total()
.with_label_values(&[reason])
.inc();
}
pub(crate) fn record_search_index_rebuild(cause: &str) {
search_index_rebuild_total()
.with_label_values(&[cause])
.inc();
}
pub(crate) fn record_search_index_barrier_held() {
search_index_barrier_held_total().inc();
}
pub(crate) fn record_search_index_reconcile(cleared: bool, refused: usize) {
search_index_reconcile_total()
.with_label_values(&[if cleared { "true" } else { "false" }])
.inc();
search_index_reconcile_refused().set(i64::try_from(refused).unwrap_or(i64::MAX));
}
pub(crate) fn record_search_index_queue(pending: usize, degraded: bool) {
search_index_pending_partitions().set(i64::try_from(pending).unwrap_or(i64::MAX));
search_index_degraded().set(i64::from(degraded));
}
pub(crate) fn record_cache_hit() {
cache_hit_total().inc();
}
pub(crate) fn record_cache_tail() {
cache_tail_total().inc();
}
pub(crate) fn record_cache_full_rebuild() {
cache_full_rebuild_total().inc();
}
pub(crate) fn record_cache_eviction() {
cache_eviction_total().inc();
}
pub(crate) fn record_cached_volume_budget_exceeded(scope: &str) {
cached_volume_budget_exceeded_total()
.with_label_values(&[scope])
.inc();
}
pub(crate) fn force() {
for scope in SCOPE_LABELS {
source_events().with_label_values(&[scope]);
replayed_bytes().with_label_values(&[scope]);
cached_scan_events().with_label_values(&[scope]);
cached_scan_bytes().with_label_values(&[scope]);
source_budget_exceeded_total().with_label_values(&[scope]);
cached_volume_budget_exceeded_total().with_label_values(&[scope]);
}
for reason in SEARCH_UNAVAILABLE_REASONS {
search_index_unavailable_total().with_label_values(&[reason]);
}
for cause in SEARCH_REBUILD_CAUSES {
search_index_rebuild_total().with_label_values(&[cause]);
}
for cleared in ["true", "false"] {
search_index_reconcile_total().with_label_values(&[cleared]);
}
cache_hit_total();
cache_tail_total();
cache_full_rebuild_total();
cache_eviction_total();
search_index_barrier_held_total();
search_index_reconcile_refused();
search_index_pending_partitions();
search_index_degraded();
}
#[cfg(test)]
mod tests {
#![allow(clippy::pedantic, clippy::nursery, missing_docs)]
use prometheus::{Encoder as _, TextEncoder};
use super::{
record_cache_eviction, record_cache_full_rebuild, record_cache_hit, record_cache_tail,
record_cached_scan_volume, record_cached_volume_budget_exceeded, record_query_observed,
record_query_replayed_bytes, record_search_index_barrier_held, record_search_index_queue,
record_search_index_rebuild, record_search_index_reconcile,
record_search_index_unavailable, record_source_budget_exceeded,
};
fn scrape() -> String {
let mut buf = Vec::new();
TextEncoder::new()
.encode(&prometheus::default_registry().gather(), &mut buf)
.expect("encode");
String::from_utf8(buf).expect("utf8")
}
#[test]
fn record_query_observed_is_visible_in_a_registry_scrape() {
record_query_observed("fleet", 42, 4_096);
let text = scrape();
assert!(
text.contains("polychrome_query_source_events_bucket"),
"missing source-events histogram buckets in scrape:\n{text}"
);
assert!(
text.contains("polychrome_query_replayed_bytes_bucket"),
"missing replayed-bytes histogram buckets in scrape:\n{text}"
);
assert!(text.contains("scope=\"fleet\""));
}
#[test]
fn the_search_index_series_are_visible_in_a_registry_scrape() {
record_search_index_unavailable("replay_budget_exceeded");
record_search_index_rebuild("excision");
record_search_index_barrier_held();
record_search_index_reconcile(false, 3);
record_search_index_queue(7, true);
let text = scrape();
for series in [
"polychrome_search_index_unavailable_total",
"polychrome_search_index_rebuild_total",
"polychrome_search_index_barrier_held_total",
"polychrome_search_index_reconcile_total",
"polychrome_search_index_reconcile_refused",
"polychrome_search_index_pending_partitions",
"polychrome_search_index_degraded",
] {
assert!(text.contains(series), "missing {series} in scrape:\n{text}");
}
assert!(text.contains("reason=\"replay_budget_exceeded\""));
assert!(text.contains("cleared=\"false\""));
assert!(
text.contains("polychrome_search_index_degraded 1"),
"the degraded gauge must carry the state, not merely exist:\n{text}"
);
}
#[test]
fn record_query_replayed_bytes_is_visible_in_a_registry_scrape() {
record_query_replayed_bytes("conversations", 20_000_000);
let text = scrape();
assert!(
text.contains("polychrome_query_replayed_bytes_bucket"),
"missing replayed-bytes histogram buckets in scrape:\n{text}"
);
assert!(text.contains("scope=\"conversations\""));
}
#[test]
fn record_source_budget_exceeded_increments_by_exactly_one() {
let metric = "polychrome_query_source_budget_exceeded_total";
let before = labeled_counter_value(&scrape(), metric, "grant");
record_source_budget_exceeded("grant");
let after = labeled_counter_value(&scrape(), metric, "grant");
assert_eq!(
after - before,
1.0,
"{metric}{{scope=\"grant\"}} must increment by exactly 1"
);
}
#[test]
fn record_cached_scan_volume_is_visible_in_a_registry_scrape() {
record_cached_scan_volume("persona", 7, 2_048);
let text = scrape();
assert!(
text.contains("polychrome_query_cached_scan_events_bucket"),
"missing cached-scan-events histogram buckets in scrape:\n{text}"
);
assert!(
text.contains("polychrome_query_cached_scan_bytes_bucket"),
"missing cached-scan-bytes histogram buckets in scrape:\n{text}"
);
assert!(text.contains("scope=\"persona\""));
}
#[test]
fn record_cached_volume_budget_exceeded_increments_by_exactly_one() {
let metric = "polychrome_query_cached_volume_budget_exceeded_total";
let before = labeled_counter_value(&scrape(), metric, "fleet");
record_cached_volume_budget_exceeded("fleet");
let after = labeled_counter_value(&scrape(), metric, "fleet");
assert_eq!(
after - before,
1.0,
"{metric}{{scope=\"fleet\"}} must increment by exactly 1"
);
}
#[test]
fn record_cache_hit_increments_by_exactly_one() {
let metric = "polychrome_query_cache_hit_total";
let before = bare_counter_value(&scrape(), metric);
record_cache_hit();
let after = bare_counter_value(&scrape(), metric);
assert_eq!(after - before, 1.0, "{metric} must increment by exactly 1");
}
#[test]
fn record_cache_tail_increments_by_exactly_one() {
let metric = "polychrome_query_cache_tail_total";
let before = bare_counter_value(&scrape(), metric);
record_cache_tail();
let after = bare_counter_value(&scrape(), metric);
assert_eq!(after - before, 1.0, "{metric} must increment by exactly 1");
}
#[test]
fn record_cache_full_rebuild_increments_by_exactly_one() {
let metric = "polychrome_query_cache_full_rebuild_total";
let before = bare_counter_value(&scrape(), metric);
record_cache_full_rebuild();
let after = bare_counter_value(&scrape(), metric);
assert_eq!(after - before, 1.0, "{metric} must increment by exactly 1");
}
#[test]
fn record_cache_eviction_increments_by_exactly_one() {
let metric = "polychrome_query_cache_eviction_total";
let before = bare_counter_value(&scrape(), metric);
record_cache_eviction();
let after = bare_counter_value(&scrape(), metric);
assert_eq!(after - before, 1.0, "{metric} must increment by exactly 1");
}
fn labeled_counter_value(text: &str, metric: &str, scope: &str) -> f64 {
let needle = format!("{metric}{{scope=\"{scope}\"}} ");
text.lines()
.find(|line| line.starts_with(&needle))
.and_then(|line| line.rsplit(' ').next())
.and_then(|v| v.parse::<f64>().ok())
.unwrap_or(0.0)
}
fn bare_counter_value(text: &str, metric: &str) -> f64 {
let needle = format!("{metric} ");
text.lines()
.find(|line| line.starts_with(&needle))
.and_then(|line| line.rsplit(' ').next())
.and_then(|v| v.parse::<f64>().ok())
.unwrap_or(0.0)
}
}