use super::catalog::ALL_METRICS;
use super::operator_docs_annotations::ANNOTATIONS;
pub const COMMITTED_DOC_REL: &str = "docs/reports/flight-metrics-reference.md";
pub const WEBSITE_DOC_REL: &str =
"website/src/content/docs/agents-using/flight-metrics-reference.md";
const WEBSITE_FRONT_MATTER: &str = "\
---
title: Flight metrics reference
description: Operator reference for every cqlite.* instrument CQLite emits over Arrow Flight and the storage/write/compaction paths — generated from the observability catalog so it cannot drift.
sidebar:
label: Flight metrics reference
order: 20
---
";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetricKind {
Counter,
Gauge,
Histogram,
}
impl MetricKind {
pub fn label(self) -> &'static str {
match self {
MetricKind::Counter => "counter",
MetricKind::Gauge => "gauge",
MetricKind::Histogram => "histogram",
}
}
}
#[derive(Debug, Clone)]
pub struct MetricDoc {
pub name: &'static str,
pub kind: MetricKind,
pub unit: &'static str,
pub summary: &'static str,
pub attributes: &'static [&'static str],
pub interpretation: &'static str,
pub round_item: &'static str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DocGenError {
MissingAnnotation(&'static str),
UnknownMetric(&'static str),
DuplicateAnnotation(&'static str),
}
impl std::fmt::Display for DocGenError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DocGenError::MissingAnnotation(m) => write!(
f,
"metric `{m}` is catalogued but has no operator annotation in \
operator_docs::ANNOTATIONS — no undocumented instrument may ship (#2426)"
),
DocGenError::UnknownMetric(m) => write!(
f,
"operator annotation names `{m}`, which is not in catalog::ALL_METRICS \
(stale annotation)"
),
DocGenError::DuplicateAnnotation(m) => {
write!(f, "operator annotation for `{m}` appears more than once")
}
}
}
}
impl std::error::Error for DocGenError {}
pub fn operator_metric_docs() -> Result<Vec<MetricDoc>, DocGenError> {
let mut seen = std::collections::HashSet::new();
for a in ANNOTATIONS {
if !seen.insert(a.name) {
return Err(DocGenError::DuplicateAnnotation(a.name));
}
if !ALL_METRICS.contains(&a.name) {
return Err(DocGenError::UnknownMetric(a.name));
}
}
let mut out = Vec::with_capacity(ALL_METRICS.len());
for name in ALL_METRICS {
match ANNOTATIONS.iter().find(|a| a.name == *name) {
Some(a) => out.push(a.clone()),
None => return Err(DocGenError::MissingAnnotation(name)),
}
}
Ok(out)
}
pub fn render_markdown() -> Result<String, DocGenError> {
let mut docs = operator_metric_docs()?;
docs.sort_by(|a, b| a.name.cmp(b.name));
let mut s = String::new();
let mut line = |t: &str| {
s.push_str(t);
s.push('\n');
};
line("# CQLite Flight metrics — operator reference");
line("");
line(
"> GENERATED from the observability catalog \
(`cqlite-core/src/observability/catalog.rs` + `operator_docs.rs`) by \
`cargo run -p cqlite-core --example gen_operator_metrics_doc`. \
Do NOT edit by hand — edit the catalog/annotations and regenerate. \
The `operator-metrics-doc` agent-gate component fails if this file drifts \
from the catalog (issue #2426).",
);
line("");
line(
"Operator-facing reference for every `cqlite.*` instrument CQLite emits \
over Arrow Flight and the storage/write/compaction paths. Names, units, \
and bounded attribute sets come straight from the code, so this page \
cannot silently diverge from what a running server exposes.",
);
line("");
line("Related: the Flight/Trino operator docs (`docs/flight-trino/`) and the round scoreboard template (issue #2399) link back to the entries here.");
line("");
line(&format!("Total instruments: **{}**.", docs.len()));
line("");
line("## All instruments");
line("");
line("| Metric | Type | Unit | Attributes | Operator meaning | Healthy vs alarming |");
line("|---|---|---|---|---|---|");
for d in &docs {
let attrs = if d.attributes.is_empty() {
"_(none)_".to_string()
} else {
d.attributes
.iter()
.map(|a| format!("`{a}`"))
.collect::<Vec<_>>()
.join("<br>")
};
line(&format!(
"| `{}` | {} | `{}` | {} | {} | {} |",
d.name,
d.kind.label(),
d.unit,
attrs,
d.summary,
d.interpretation,
));
}
line("");
line("## Round-scoreboard mapping (issue #2399)");
line("");
line("Metrics a #2399 round-template scoreboard item consumes. Round handoffs (#2367-style) link the item to its metric here instead of re-explaining it.");
line("");
line("| Metric | Scoreboard item |");
line("|---|---|");
let mut any = false;
for d in &docs {
if d.round_item != "—" {
any = true;
line(&format!("| `{}` | {} |", d.name, d.round_item));
}
}
if !any {
line("| _(none)_ | _(none)_ |");
}
line("");
Ok(s)
}
pub fn render_website_markdown() -> Result<String, DocGenError> {
Ok(format!("{WEBSITE_FRONT_MATTER}{}", render_markdown()?))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_catalogued_metric_has_an_operator_annotation() {
let docs = operator_metric_docs().expect("every ALL_METRICS entry must be annotated");
assert_eq!(
docs.len(),
ALL_METRICS.len(),
"operator doc count must equal the catalog metric count"
);
}
#[test]
fn no_annotation_names_a_metric_absent_from_the_catalog() {
for a in ANNOTATIONS {
assert!(
ALL_METRICS.contains(&a.name),
"annotation names `{}`, absent from ALL_METRICS",
a.name
);
}
}
#[test]
fn attributes_are_catalogued_bounded_keys() {
let docs = operator_metric_docs().unwrap();
for d in &docs {
for a in d.attributes {
assert!(
a.starts_with("cqlite."),
"attribute `{a}` on `{}` must be a namespaced bounded key",
d.name
);
}
}
}
#[test]
fn render_is_deterministic_and_non_empty() {
let a = render_markdown().unwrap();
let b = render_markdown().unwrap();
assert_eq!(a, b, "render must be byte-stable across runs");
assert!(a.contains("# CQLite Flight metrics — operator reference"));
for name in ALL_METRICS {
assert!(a.contains(name), "rendered doc must mention `{name}`");
}
}
#[test]
fn committed_operator_metrics_doc_is_fresh() {
let repo_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("cqlite-core has a repo-root parent");
let path = repo_root.join(COMMITTED_DOC_REL);
let committed = std::fs::read_to_string(&path).unwrap_or_else(|e| {
panic!(
"committed operator metrics doc {} is missing ({e}); regenerate with \
`cargo run -p cqlite-core --example gen_operator_metrics_doc`",
path.display()
)
});
let fresh = render_markdown().expect("render must succeed");
assert_eq!(
committed,
fresh,
"{} is STALE vs the catalog; regenerate with \
`cargo run -p cqlite-core --example gen_operator_metrics_doc`",
path.display()
);
let web_path = repo_root.join(WEBSITE_DOC_REL);
let web_committed = std::fs::read_to_string(&web_path).unwrap_or_else(|e| {
panic!(
"published website metrics page {} is missing ({e}); regenerate with \
`cargo run -p cqlite-core --example gen_operator_metrics_doc`",
web_path.display()
)
});
let web_fresh = render_website_markdown().expect("website render must succeed");
assert_eq!(
web_committed,
web_fresh,
"{} is STALE vs the catalog; regenerate with \
`cargo run -p cqlite-core --example gen_operator_metrics_doc`",
web_path.display()
);
}
#[test]
fn missing_annotation_is_detected() {
let e = DocGenError::MissingAnnotation("cqlite.example.unannotated");
assert!(e.to_string().contains("no operator annotation"));
let u = DocGenError::UnknownMetric("cqlite.example.stale");
assert!(u.to_string().contains("not in catalog::ALL_METRICS"));
}
}