20260826 增加BER兼容告警与分类指标
This commit is contained in:
@@ -424,6 +424,7 @@ struct LatestRunMetrics {
|
||||
vaps: u64,
|
||||
publication_points: u64,
|
||||
warnings: u64,
|
||||
warning_categories: BTreeMap<String, u64>,
|
||||
tree_instances_processed: Option<u64>,
|
||||
tree_instances_failed: Option<u64>,
|
||||
stage_seconds: BTreeMap<String, f64>,
|
||||
@@ -1477,13 +1478,9 @@ fn parse_report(path: &Path, snapshot: &mut MetricsSnapshot, latest: &mut Latest
|
||||
.map(|a| a.len() as u64)
|
||||
.unwrap_or(0);
|
||||
}
|
||||
latest.warnings = latest.warnings.max(
|
||||
report
|
||||
.pointer("/tree/warnings")
|
||||
.and_then(|v| v.as_array())
|
||||
.map(|a| a.len() as u64)
|
||||
.unwrap_or(0),
|
||||
);
|
||||
let (reported_warning_count, warning_categories) = collect_warning_categories(&report);
|
||||
latest.warnings = latest.warnings.max(reported_warning_count);
|
||||
latest.warning_categories = warning_categories;
|
||||
if let Some(processed) = json_u64(&report, &["tree", "instances_processed"]) {
|
||||
latest.tree_instances_processed = Some(processed);
|
||||
}
|
||||
@@ -1504,6 +1501,47 @@ fn parse_report(path: &Path, snapshot: &mut MetricsSnapshot, latest: &mut Latest
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_warning_categories(report: &Value) -> (u64, BTreeMap<String, u64>) {
|
||||
let mut total = 0u64;
|
||||
let mut categories = BTreeMap::new();
|
||||
total += count_warning_categories(
|
||||
report.pointer("/tree/warnings").and_then(Value::as_array),
|
||||
&mut categories,
|
||||
);
|
||||
if let Some(publication_points) = report.get("publication_points").and_then(Value::as_array) {
|
||||
for publication_point in publication_points {
|
||||
total += count_warning_categories(
|
||||
publication_point.get("warnings").and_then(Value::as_array),
|
||||
&mut categories,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Export the baseline and BER-compatibility series even when their count is
|
||||
// zero, so dashboards can distinguish a clean run from a missing metric.
|
||||
for category in ["unclassified", "ber_compatible_cms_encoding"] {
|
||||
categories.entry(category.to_string()).or_insert(0);
|
||||
}
|
||||
(total, categories)
|
||||
}
|
||||
|
||||
fn count_warning_categories(
|
||||
warnings: Option<&Vec<Value>>,
|
||||
categories: &mut BTreeMap<String, u64>,
|
||||
) -> u64 {
|
||||
let Some(warnings) = warnings else {
|
||||
return 0;
|
||||
};
|
||||
for warning in warnings {
|
||||
let category = warning
|
||||
.get("category")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or("unclassified");
|
||||
*categories.entry(category.to_string()).or_default() += 1;
|
||||
}
|
||||
warnings.len() as u64
|
||||
}
|
||||
|
||||
fn extract_publication_point_metrics(
|
||||
pps: &[Value],
|
||||
downloads: Option<&Value>,
|
||||
@@ -2409,6 +2447,17 @@ fn render_latest_metrics(writer: &mut PromWriter<'_>, instance: &str, latest: &L
|
||||
&[label("instance", instance)],
|
||||
latest.warnings as f64,
|
||||
);
|
||||
for (category, count) in &latest.warning_categories {
|
||||
writer.gauge(
|
||||
"ours_rp_warnings_by_category",
|
||||
"Latest run warning count by category",
|
||||
&[
|
||||
label("instance", instance),
|
||||
label("warning_category", category),
|
||||
],
|
||||
*count as f64,
|
||||
);
|
||||
}
|
||||
if let Some(value) = latest.tree_instances_processed {
|
||||
writer.gauge(
|
||||
"ours_rp_tree_instances",
|
||||
@@ -3364,6 +3413,48 @@ mod tests {
|
||||
assert_eq!(args.out_metrics.as_deref(), Some(Path::new("metrics.prom")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warning_categories_cover_tree_and_publication_point_warnings() {
|
||||
let report = json!({
|
||||
"tree": {
|
||||
"warnings": [
|
||||
{"category": "ber_compatible_cms_encoding"},
|
||||
{"category": "ber_compatible_cms_encoding"}
|
||||
]
|
||||
},
|
||||
"publication_points": [
|
||||
{"warnings": [{"category": "repository_sync"}]},
|
||||
{"warnings": [{"message": "legacy warning without category"}]}
|
||||
]
|
||||
});
|
||||
|
||||
let (total, categories) = collect_warning_categories(&report);
|
||||
assert_eq!(total, 4);
|
||||
assert_eq!(categories["ber_compatible_cms_encoding"], 2);
|
||||
assert_eq!(categories["repository_sync"], 1);
|
||||
assert_eq!(categories["unclassified"], 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn renders_warning_category_metrics() {
|
||||
let mut warning_categories = BTreeMap::new();
|
||||
warning_categories.insert("ber_compatible_cms_encoding".to_string(), 2);
|
||||
let snapshot = MetricsSnapshot {
|
||||
instance: "test".to_string(),
|
||||
latest_run: Some(LatestRunMetrics {
|
||||
warnings: 2,
|
||||
warning_categories,
|
||||
..LatestRunMetrics::default()
|
||||
}),
|
||||
..MetricsSnapshot::default()
|
||||
};
|
||||
|
||||
let metrics = render_metrics(&snapshot);
|
||||
assert!(metrics.contains(
|
||||
r#"ours_rp_warnings_by_category{instance="test",warning_category="ber_compatible_cms_encoding"} 2"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scan_fixture_exports_repo_pp_cir_and_ccr_metrics() {
|
||||
let td = TempDir::new().expect("tempdir");
|
||||
|
||||
Reference in New Issue
Block a user