fix(obs): export resettable metrics as gauges (#4432)

Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
houseme
2026-07-08 16:23:11 +08:00
committed by GitHub
parent d7b55c9762
commit acb1b765db
7 changed files with 82 additions and 17 deletions
@@ -72,6 +72,7 @@ pub fn collect_audit_metrics(stats: &[AuditTargetStats]) -> Vec<PrometheusMetric
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::metrics::schema::MetricType;
#[test] #[test]
fn test_collect_audit_metrics() { fn test_collect_audit_metrics() {
@@ -106,4 +107,11 @@ mod tests {
let metrics = collect_audit_metrics(&stats); let metrics = collect_audit_metrics(&stats);
assert!(metrics.is_empty()); assert!(metrics.is_empty());
} }
#[test]
fn audit_target_totals_are_exported_as_gauges() {
assert_eq!(AUDIT_FAILED_MESSAGES_MD.metric_type, MetricType::Gauge);
assert_eq!(AUDIT_TARGET_QUEUE_LENGTH_MD.metric_type, MetricType::Gauge);
assert_eq!(AUDIT_TOTAL_MESSAGES_MD.metric_type, MetricType::Gauge);
}
} }
@@ -87,6 +87,7 @@ pub fn collect_iam_metrics(stats: &IamStats) -> Vec<PrometheusMetric> {
mod tests { mod tests {
use super::*; use super::*;
use crate::metrics::report::report_metrics; use crate::metrics::report::report_metrics;
use crate::metrics::schema::MetricType;
#[test] #[test]
fn test_collect_iam_metrics() { fn test_collect_iam_metrics() {
@@ -125,4 +126,25 @@ mod tests {
assert!(metric.labels.is_empty()); assert!(metric.labels.is_empty());
} }
} }
#[test]
fn iam_metric_descriptors_preserve_gauge_vs_counter_semantics() {
let gauge_descriptors = [
&LAST_SYNC_DURATION_MILLIS_MD,
&PLUGIN_AUTHN_SERVICE_FAILED_REQUESTS_MINUTE_MD,
&PLUGIN_AUTHN_SERVICE_LAST_FAIL_SECONDS_MD,
&PLUGIN_AUTHN_SERVICE_LAST_SUCC_SECONDS_MD,
&PLUGIN_AUTHN_SERVICE_SUCC_AVG_RTT_MS_MINUTE_MD,
&PLUGIN_AUTHN_SERVICE_SUCC_MAX_RTT_MS_MINUTE_MD,
&PLUGIN_AUTHN_SERVICE_TOTAL_REQUESTS_MINUTE_MD,
&SINCE_LAST_SYNC_MILLIS_MD,
];
for descriptor in gauge_descriptors {
assert_eq!(descriptor.metric_type, MetricType::Gauge);
}
assert_eq!(SYNC_FAILURES_MD.metric_type, MetricType::Counter);
assert_eq!(SYNC_SUCCESSES_MD.metric_type, MetricType::Counter);
}
} }
@@ -63,6 +63,7 @@ pub fn collect_notification_target_metrics(stats: &[NotificationTargetStats]) ->
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::metrics::schema::MetricType;
#[test] #[test]
fn test_collect_notification_target_metrics() { fn test_collect_notification_target_metrics() {
@@ -89,4 +90,11 @@ mod tests {
.any(|(key, value)| *key == TARGET_TYPE && value == "webhook") .any(|(key, value)| *key == TARGET_TYPE && value == "webhook")
})); }));
} }
#[test]
fn notification_target_totals_are_exported_as_gauges() {
assert_eq!(NOTIFICATION_TARGET_FAILED_MESSAGES_MD.metric_type, MetricType::Gauge);
assert_eq!(NOTIFICATION_TARGET_QUEUE_LENGTH_MD.metric_type, MetricType::Gauge);
assert_eq!(NOTIFICATION_TARGET_TOTAL_MESSAGES_MD.metric_type, MetricType::Gauge);
}
} }
+29 -2
View File
@@ -38,6 +38,18 @@ fn into_static_str(cache: &OnceLock<Mutex<HashMap<String, &'static str>>>, value
intern_string(cache, value) intern_string(cache, value)
} }
fn counter_value_from_f64(value: f64) -> Option<u64> {
if !value.is_finite() || value < 0.0 {
return None;
}
if value >= u64::MAX as f64 {
Some(u64::MAX)
} else {
Some(value as u64)
}
}
pub fn report_metrics(metrics: &[PrometheusMetric]) { pub fn report_metrics(metrics: &[PrometheusMetric]) {
for metric in metrics { for metric in metrics {
let name = into_static_str(&NAME_CACHE, &metric.name); let name = into_static_str(&NAME_CACHE, &metric.name);
@@ -53,8 +65,10 @@ pub fn report_metrics(metrics: &[PrometheusMetric]) {
match metric.metric_type { match metric.metric_type {
MetricType::Counter => { MetricType::Counter => {
let counter = counter!(name, &labels); if let Some(value) = counter_value_from_f64(metric.value) {
counter.absolute(metric.value as u64); let counter = counter!(name, &labels);
counter.absolute(value);
}
} }
MetricType::Gauge => { MetricType::Gauge => {
let gauge = gauge!(name, &labels); let gauge = gauge!(name, &labels);
@@ -168,4 +182,17 @@ mod tests {
assert_eq!(metric.metric_type, metric_type); assert_eq!(metric.metric_type, metric_type);
} }
} }
#[test]
fn counter_value_from_f64_rejects_negative_and_nan_inputs() {
assert_eq!(counter_value_from_f64(-1.0), None);
assert_eq!(counter_value_from_f64(f64::NAN), None);
assert_eq!(counter_value_from_f64(f64::NEG_INFINITY), None);
}
#[test]
fn counter_value_from_f64_clamps_large_values() {
assert_eq!(counter_value_from_f64(42.0), Some(42));
assert_eq!(counter_value_from_f64(u64::MAX as f64 * 2.0), Some(u64::MAX));
}
} }
+3 -3
View File
@@ -14,7 +14,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::{MetricDescriptor, MetricName, new_counter_md, new_gauge_md, subsystems}; use crate::{MetricDescriptor, MetricName, new_gauge_md, subsystems};
use std::sync::LazyLock; use std::sync::LazyLock;
const TARGET_ID: &str = "target_id"; const TARGET_ID: &str = "target_id";
@@ -25,7 +25,7 @@ pub const SUCCESS: &str = "success";
pub const FAILURE: &str = "failure"; pub const FAILURE: &str = "failure";
pub static AUDIT_FAILED_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static AUDIT_FAILED_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::AuditFailedMessages, MetricName::AuditFailedMessages,
"Total number of messages that failed to send since start", "Total number of messages that failed to send since start",
&[TARGET_ID], &[TARGET_ID],
@@ -43,7 +43,7 @@ pub static AUDIT_TARGET_QUEUE_LENGTH_MD: LazyLock<MetricDescriptor> = LazyLock::
}); });
pub static AUDIT_TOTAL_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static AUDIT_TOTAL_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::AuditTotalMessages, MetricName::AuditTotalMessages,
"Total number of messages sent since start", "Total number of messages sent since start",
&[TARGET_ID], &[TARGET_ID],
+9 -9
View File
@@ -14,11 +14,11 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::{MetricDescriptor, MetricName, new_counter_md, subsystems}; use crate::{MetricDescriptor, MetricName, new_counter_md, new_gauge_md, subsystems};
use std::sync::LazyLock; use std::sync::LazyLock;
pub static LAST_SYNC_DURATION_MILLIS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static LAST_SYNC_DURATION_MILLIS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::LastSyncDurationMillis, MetricName::LastSyncDurationMillis,
"Last successful IAM data sync duration in milliseconds", "Last successful IAM data sync duration in milliseconds",
&[], &[],
@@ -27,7 +27,7 @@ pub static LAST_SYNC_DURATION_MILLIS_MD: LazyLock<MetricDescriptor> = LazyLock::
}); });
pub static PLUGIN_AUTHN_SERVICE_FAILED_REQUESTS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_FAILED_REQUESTS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceFailedRequestsMinute, MetricName::PluginAuthnServiceFailedRequestsMinute,
"When plugin authentication is configured, returns failed requests count in the last full minute", "When plugin authentication is configured, returns failed requests count in the last full minute",
&[], &[],
@@ -36,7 +36,7 @@ pub static PLUGIN_AUTHN_SERVICE_FAILED_REQUESTS_MINUTE_MD: LazyLock<MetricDescri
}); });
pub static PLUGIN_AUTHN_SERVICE_LAST_FAIL_SECONDS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_LAST_FAIL_SECONDS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceLastFailSeconds, MetricName::PluginAuthnServiceLastFailSeconds,
"When plugin authentication is configured, returns time (in seconds) since the last failed request to the service", "When plugin authentication is configured, returns time (in seconds) since the last failed request to the service",
&[], &[],
@@ -45,7 +45,7 @@ pub static PLUGIN_AUTHN_SERVICE_LAST_FAIL_SECONDS_MD: LazyLock<MetricDescriptor>
}); });
pub static PLUGIN_AUTHN_SERVICE_LAST_SUCC_SECONDS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_LAST_SUCC_SECONDS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceLastSuccSeconds, MetricName::PluginAuthnServiceLastSuccSeconds,
"When plugin authentication is configured, returns time (in seconds) since the last successful request to the service", "When plugin authentication is configured, returns time (in seconds) since the last successful request to the service",
&[], &[],
@@ -54,7 +54,7 @@ pub static PLUGIN_AUTHN_SERVICE_LAST_SUCC_SECONDS_MD: LazyLock<MetricDescriptor>
}); });
pub static PLUGIN_AUTHN_SERVICE_SUCC_AVG_RTT_MS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_SUCC_AVG_RTT_MS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceSuccAvgRttMsMinute, MetricName::PluginAuthnServiceSuccAvgRttMsMinute,
"When plugin authentication is configured, returns average round-trip-time of successful requests in the last full minute", "When plugin authentication is configured, returns average round-trip-time of successful requests in the last full minute",
&[], &[],
@@ -63,7 +63,7 @@ pub static PLUGIN_AUTHN_SERVICE_SUCC_AVG_RTT_MS_MINUTE_MD: LazyLock<MetricDescri
}); });
pub static PLUGIN_AUTHN_SERVICE_SUCC_MAX_RTT_MS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_SUCC_MAX_RTT_MS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceSuccMaxRttMsMinute, MetricName::PluginAuthnServiceSuccMaxRttMsMinute,
"When plugin authentication is configured, returns maximum round-trip-time of successful requests in the last full minute", "When plugin authentication is configured, returns maximum round-trip-time of successful requests in the last full minute",
&[], &[],
@@ -72,7 +72,7 @@ pub static PLUGIN_AUTHN_SERVICE_SUCC_MAX_RTT_MS_MINUTE_MD: LazyLock<MetricDescri
}); });
pub static PLUGIN_AUTHN_SERVICE_TOTAL_REQUESTS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static PLUGIN_AUTHN_SERVICE_TOTAL_REQUESTS_MINUTE_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::PluginAuthnServiceTotalRequestsMinute, MetricName::PluginAuthnServiceTotalRequestsMinute,
"When plugin authentication is configured, returns total requests count in the last full minute", "When plugin authentication is configured, returns total requests count in the last full minute",
&[], &[],
@@ -81,7 +81,7 @@ pub static PLUGIN_AUTHN_SERVICE_TOTAL_REQUESTS_MINUTE_MD: LazyLock<MetricDescrip
}); });
pub static SINCE_LAST_SYNC_MILLIS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static SINCE_LAST_SYNC_MILLIS_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::SinceLastSyncMillis, MetricName::SinceLastSyncMillis,
"Time (in milliseconds) since last successful IAM data sync.", "Time (in milliseconds) since last successful IAM data sync.",
&[], &[],
@@ -14,7 +14,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use crate::{MetricDescriptor, MetricName, new_counter_md, new_gauge_md, subsystems}; use crate::{MetricDescriptor, MetricName, new_gauge_md, subsystems};
use std::sync::LazyLock; use std::sync::LazyLock;
pub const TARGET_ID: &str = "target_id"; pub const TARGET_ID: &str = "target_id";
@@ -23,7 +23,7 @@ pub const TARGET_TYPE: &str = "target_type";
const NOTIFICATION_TARGET_LABELS: [&str; 2] = [TARGET_ID, TARGET_TYPE]; const NOTIFICATION_TARGET_LABELS: [&str; 2] = [TARGET_ID, TARGET_TYPE];
pub static NOTIFICATION_TARGET_FAILED_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static NOTIFICATION_TARGET_FAILED_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::NotificationTargetFailedMessages, MetricName::NotificationTargetFailedMessages,
"Total number of notification messages that permanently failed to send", "Total number of notification messages that permanently failed to send",
&NOTIFICATION_TARGET_LABELS, &NOTIFICATION_TARGET_LABELS,
@@ -41,7 +41,7 @@ pub static NOTIFICATION_TARGET_QUEUE_LENGTH_MD: LazyLock<MetricDescriptor> = Laz
}); });
pub static NOTIFICATION_TARGET_TOTAL_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| { pub static NOTIFICATION_TARGET_TOTAL_MESSAGES_MD: LazyLock<MetricDescriptor> = LazyLock::new(|| {
new_counter_md( new_gauge_md(
MetricName::NotificationTargetTotalMessages, MetricName::NotificationTargetTotalMessages,
"Total number of notification messages successfully delivered", "Total number of notification messages successfully delivered",
&NOTIFICATION_TARGET_LABELS, &NOTIFICATION_TARGET_LABELS,