refactor(metrics): migrate scanner report timestamps to jiff (#5710)

* refactor(metrics): migrate scanner report timestamps to jiff

Co-Authored-By: heihutu <heihutu@gmail.com>

* refactor(madmin): migrate admin timestamps to jiff (#5712)

Co-authored-by: heihutu <heihutu@gmail.com>

* refactor(storage): migrate RPC DTO timestamps to jiff (#5713)

Co-authored-by: heihutu <heihutu@gmail.com>

---------

Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
houseme
2026-08-05 02:35:38 +08:00
committed by GitHub
parent 3dabac4a09
commit 16c2928965
14 changed files with 458 additions and 115 deletions
+1
View File
@@ -149,6 +149,7 @@ async-trait.workspace = true
bytes = { workspace = true, features = ["serde"] }
byteorder = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
jiff = { workspace = true, features = ["serde"] }
glob = { workspace = true }
thiserror.workspace = true
flatbuffers.workspace = true
@@ -13,6 +13,7 @@
// limitations under the License.
use crate::error::{Error, Result};
use jiff::Timestamp;
use rmp_serde::Serializer as rmpSerializer;
use serde::{Deserialize, Serialize};
use std::{
@@ -32,7 +33,7 @@ pub struct Credentials {
#[serde(rename = "secretKey")]
pub secret_key: String,
pub session_token: Option<String>,
pub expiration: Option<chrono::DateTime<chrono::Utc>>,
pub expiration: Option<Timestamp>,
}
impl Credentials {
@@ -408,7 +409,11 @@ mod tests {
assert_eq!(credentials.access_key, "test-access-key");
assert_eq!(credentials.secret_key, "test-secret-key");
assert_eq!(credentials.session_token, Some("test-session-token".to_string()));
assert!(credentials.expiration.is_some());
assert_eq!(
serde_json::to_value(credentials.expiration.expect("expiration should parse"))
.expect("expiration should serialize to JSON"),
serde_json::json!("2024-12-31T23:59:59Z")
);
// Verify latency statistics
assert_eq!(target.latency.curr, Duration::from_millis(100));
@@ -562,12 +567,15 @@ mod tests {
.and_then(|credentials| credentials.session_token.as_deref()),
Some("legacy-session-token")
);
assert!(
assert_eq!(
target
.credentials
.as_ref()
.and_then(|credentials| credentials.expiration)
.is_some()
.map(serde_json::to_value)
.transpose()
.expect("expiration should serialize to JSON"),
Some(serde_json::json!("2024-12-31T23:59:59Z"))
);
}
@@ -609,7 +617,11 @@ mod tests {
credentials.session_token,
Some("AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT".to_string())
);
assert!(credentials.expiration.is_some());
assert_eq!(
serde_json::to_value(credentials.expiration.expect("expiration should parse"))
.expect("expiration should serialize to JSON"),
serde_json::json!("2024-12-31T23:59:59Z")
);
}
#[test]
@@ -15,7 +15,9 @@
use crate::diagnostics::admin_server_info::get_local_server_property;
use crate::runtime::sources as runtime_sources;
use crate::storage_api_contracts::admin::StorageAdminApi;
#[cfg(test)]
use chrono::Utc;
use jiff::Timestamp;
use rustfs_common::{heal_channel::DriveState, metrics::global_metrics};
use rustfs_io_metrics::internode_metrics::global_internode_metrics;
use rustfs_madmin::metrics::{
@@ -67,6 +69,18 @@ impl MetricType {
}
}
fn unix_millis_to_jiff_timestamp(millis: u64, fallback: Timestamp) -> Timestamp {
let millis = match i64::try_from(millis) {
Ok(millis) => millis,
Err(_) => return fallback,
};
match Timestamp::from_millisecond(millis) {
Ok(timestamp) => timestamp,
Err(_) => fallback,
}
}
fn to_madmin_scanner_metrics(metrics: rustfs_common::metrics::ScannerMetricsReport) -> MadminScannerMetrics {
MadminScannerMetrics {
collected_at: metrics.collected_at,
@@ -386,7 +400,7 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts)
if types.contains(&MetricType::DISK) {
debug!("start get disk metrics");
let mut aggr = DiskMetric {
collected_at: Utc::now(),
collected_at: Timestamp::now(),
..Default::default()
};
for (name, disk) in collect_local_disks_metrics(&opts.disks).await.into_iter() {
@@ -412,7 +426,7 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts)
if types.contains(&MetricType::NET) {
let snapshot = global_internode_metrics().snapshot();
real_time_metrics.aggregated.net = Some(NetMetrics {
collected_at: Utc::now(),
collected_at: Timestamp::now(),
interface_name: "internode".to_string(),
net_stats: NetDevLine {
name: "internode".to_string(),
@@ -428,10 +442,9 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts)
// if types.contains(&MetricType::CPU) {}
if types.contains(&MetricType::RPC) {
let collected_at = Utc::now();
let collected_at = Timestamp::now();
let snapshot = global_internode_metrics().snapshot();
let last_connect_time =
chrono::DateTime::<Utc>::from_timestamp_millis(snapshot.last_dial_unix_millis as i64).unwrap_or(collected_at);
let last_connect_time = unix_millis_to_jiff_timestamp(snapshot.last_dial_unix_millis, collected_at);
real_time_metrics.aggregated.rpc = Some(RPCMetrics {
collected_at,
@@ -543,6 +556,10 @@ mod test {
use serial_test::serial;
use std::time::Duration;
fn chrono_to_jiff_timestamp(timestamp: chrono::DateTime<Utc>) -> jiff::Timestamp {
jiff::Timestamp::try_from(std::time::SystemTime::from(timestamp)).expect("test timestamp should fit in jiff")
}
#[test]
fn tes_types() {
let t = MetricType::ALL;
@@ -591,7 +608,7 @@ mod test {
let current_started = Utc::now() - chrono::Duration::seconds(5);
let scanner = to_madmin_scanner_metrics(rustfs_common::metrics::ScannerMetricsReport {
current_cycle_active: true,
current_started,
current_started: chrono_to_jiff_timestamp(current_started),
last_cycle_partial_source: "usage".to_string(),
last_cycle_partial_source_code: 1,
partial_cycles_by_source: vec![rustfs_common::metrics::ScannerSourceCycleSnapshot {
@@ -602,7 +619,7 @@ mod test {
});
assert_eq!(scanner.current_cycle_active, Some(true));
assert_eq!(scanner.current_started, current_started);
assert_eq!(scanner.current_started, chrono_to_jiff_timestamp(current_started));
assert_eq!(scanner.last_cycle_partial_source, "usage");
assert_eq!(scanner.last_cycle_partial_source_code, 1);
let usage = scanner
@@ -643,7 +660,7 @@ mod test {
aggregated.merge(decoded);
let scanner = aggregated.aggregated.scanner.expect("scanner metrics");
assert_eq!(scanner.current_cycle_active, Some(true));
assert_eq!(scanner.current_started, cycle_started);
assert_eq!(scanner.current_started, chrono_to_jiff_timestamp(cycle_started));
}
#[test]