fix(obs): hide unwired request metrics (#4481)

Refs rustfs/backlog#1006

- aggregate request traffic samples per type to avoid future counter collisions
- keep request schema and collector crate-internal until a production stats source exists
- preserve focused regression coverage for the internal request collector logic

Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
houseme
2026-07-08 21:08:57 +08:00
committed by GitHub
parent 0cb76e9420
commit f0bf8cfe03
3 changed files with 70 additions and 8 deletions
+1 -2
View File
@@ -28,7 +28,7 @@ pub mod node;
pub mod notification;
pub mod notification_target;
pub mod replication;
pub mod request;
pub(crate) mod request;
pub mod resource;
pub mod scanner;
pub mod system_cpu;
@@ -59,7 +59,6 @@ pub use node::{DiskStats, collect_node_metrics};
pub use notification::{NotificationStats, collect_notification_metrics};
pub use notification_target::{NotificationTargetStats, collect_notification_target_metrics};
pub use replication::{ReplicationStats, collect_replication_metrics};
pub use request::{ApiRequestStats, collect_request_metrics};
pub use resource::{ResourceStats, collect_resource_metrics};
pub use scanner::{ScannerStats, collect_scanner_metrics};
pub use system_cpu::{CpuStats, ProcessCpuStats, collect_cpu_metrics, collect_process_cpu_metrics};
+68 -5
View File
@@ -21,6 +21,7 @@
use crate::metrics::report::PrometheusMetric;
use crate::metrics::schema::request::*;
use std::collections::HashMap;
/// API request statistics for a specific API endpoint.
#[derive(Debug, Clone, Default)]
@@ -54,8 +55,13 @@ pub struct ApiRequestStats {
/// Returns a vector of Prometheus metrics for API request statistics.
pub fn collect_request_metrics(stats: &[ApiRequestStats]) -> Vec<PrometheusMetric> {
let mut metrics = Vec::new();
let mut traffic_by_type: HashMap<&str, (u64, u64)> = HashMap::with_capacity(stats.len());
for stat in stats {
let entry = traffic_by_type.entry(stat.req_type.as_str()).or_default();
entry.0 = entry.0.saturating_add(stat.sent_bytes);
entry.1 = entry.1.saturating_add(stat.recv_bytes);
// In-flight requests
metrics.push(
PrometheusMetric::from_descriptor(&API_REQUESTS_IN_FLIGHT_TOTAL_MD, stat.in_flight as f64)
@@ -107,15 +113,16 @@ pub fn collect_request_metrics(stats: &[ApiRequestStats]) -> Vec<PrometheusMetri
.with_label_owned(LE_LABEL, le.clone()),
);
}
}
// Traffic metrics
for (req_type, (sent_bytes, recv_bytes)) in traffic_by_type {
metrics.push(
PrometheusMetric::from_descriptor(&API_TRAFFIC_SENT_BYTES_MD, stat.sent_bytes as f64)
.with_label_owned(TYPE_LABEL, stat.req_type.clone()),
PrometheusMetric::from_descriptor(&API_TRAFFIC_SENT_BYTES_MD, sent_bytes as f64)
.with_label_owned(TYPE_LABEL, req_type.to_string()),
);
metrics.push(
PrometheusMetric::from_descriptor(&API_TRAFFIC_RECV_BYTES_MD, stat.recv_bytes as f64)
.with_label_owned(TYPE_LABEL, stat.req_type.clone()),
PrometheusMetric::from_descriptor(&API_TRAFFIC_RECV_BYTES_MD, recv_bytes as f64)
.with_label_owned(TYPE_LABEL, req_type.to_string()),
);
}
@@ -171,4 +178,60 @@ mod tests {
let metrics = collect_request_metrics(&stats);
assert!(metrics.is_empty());
}
#[test]
fn test_collect_request_metrics_aggregates_traffic_per_type() {
let stats = vec![
ApiRequestStats {
name: "GetObject".to_string(),
req_type: "s3".to_string(),
in_flight: 1,
total: 10,
errors_total: 0,
errors_5xx: 0,
errors_4xx: 0,
canceled: 0,
ttfb_distribution: vec![],
sent_bytes: 100,
recv_bytes: 10,
},
ApiRequestStats {
name: "HeadObject".to_string(),
req_type: "s3".to_string(),
in_flight: 2,
total: 20,
errors_total: 1,
errors_5xx: 1,
errors_4xx: 0,
canceled: 0,
ttfb_distribution: vec![],
sent_bytes: 200,
recv_bytes: 20,
},
];
let metrics = collect_request_metrics(&stats);
let sent_name = API_TRAFFIC_SENT_BYTES_MD.get_full_metric_name();
let sent_metrics: Vec<_> = metrics.iter().filter(|metric| metric.name == sent_name).collect();
assert_eq!(sent_metrics.len(), 1);
assert_eq!(sent_metrics[0].value, 300.0);
assert!(
sent_metrics[0]
.labels
.iter()
.any(|(key, value)| *key == TYPE_LABEL && value == "s3")
);
let recv_name = API_TRAFFIC_RECV_BYTES_MD.get_full_metric_name();
let recv_metrics: Vec<_> = metrics.iter().filter(|metric| metric.name == recv_name).collect();
assert_eq!(recv_metrics.len(), 1);
assert_eq!(recv_metrics[0].value, 30.0);
assert!(
recv_metrics[0]
.labels
.iter()
.any(|(key, value)| *key == TYPE_LABEL && value == "s3")
);
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ pub mod node_disk;
pub mod notification_target;
pub mod process_resource;
pub mod replication;
pub mod request;
pub(crate) mod request;
pub mod scanner;
pub mod system_cpu;
pub mod system_drive;