diff --git a/crates/common/src/globals.rs b/crates/common/src/globals.rs index d616f15f..ce708cc5 100644 --- a/crates/common/src/globals.rs +++ b/crates/common/src/globals.rs @@ -14,6 +14,7 @@ #![allow(non_upper_case_globals)] // FIXME +use chrono::{DateTime, Utc}; use std::collections::HashMap; use std::sync::LazyLock; use tokio::sync::RwLock; @@ -26,6 +27,30 @@ pub static GLOBAL_RUSTFS_ADDR: LazyLock> = LazyLock::new(|| RwLoc pub static GLOBAL_CONN_MAP: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); pub static GLOBAL_ROOT_CERT: LazyLock>>> = LazyLock::new(|| RwLock::new(None)); pub static GLOBAL_MTLS_IDENTITY: LazyLock>> = LazyLock::new(|| RwLock::new(None)); +/// Global initialization time of the RustFS node. +pub static GLOBAL_INIT_TIME: LazyLock>>> = LazyLock::new(|| RwLock::new(None)); + +/// Set the global local node name. +/// +/// # Arguments +/// * `name` - A string slice representing the local node name. +pub async fn set_global_local_node_name(name: &str) { + *GLOBAL_LOCAL_NODE_NAME.write().await = name.to_string(); +} + +/// Set the global RustFS initialization time to the current UTC time. +pub async fn set_global_init_time_now() { + let now = Utc::now(); + *GLOBAL_INIT_TIME.write().await = Some(now); +} + +/// Get the global RustFS initialization time. +/// +/// # Returns +/// * `Option>` - The initialization time if set. +pub async fn get_global_init_time() -> Option> { + *GLOBAL_INIT_TIME.read().await +} /// Set the global RustFS address used for gRPC connections. /// diff --git a/crates/common/src/metrics.rs b/crates/common/src/metrics.rs index 78b04a64..f0fc031a 100644 --- a/crates/common/src/metrics.rs +++ b/crates/common/src/metrics.rs @@ -18,6 +18,7 @@ use rustfs_madmin::metrics::ScannerMetrics as M_ScannerMetrics; use std::{ collections::HashMap, fmt::Display, + future::Future, pin::Pin, sync::{ Arc, OnceLock, @@ -115,7 +116,7 @@ pub enum Metric { impl Metric { /// Convert to string representation for metrics - pub fn as_str(self) -> &'static str { + pub fn as_str(&self) -> &'static str { match self { Self::ReadMetadata => "read_metadata", Self::CheckMissing => "check_missing", @@ -460,6 +461,11 @@ impl Metrics { metrics.current_started = cycle.started; } + // Replace default start time with global init time if it's the placeholder + if let Some(init_time) = crate::get_global_init_time().await { + metrics.current_started = init_time; + } + metrics.collected_at = Utc::now(); metrics.active_paths = self.get_current_paths().await; @@ -489,8 +495,8 @@ impl Metrics { } // Type aliases for compatibility with existing code -pub type UpdateCurrentPathFn = Arc Pin + Send>> + Send + Sync>; -pub type CloseDiskFn = Arc Pin + Send>> + Send + Sync>; +pub type UpdateCurrentPathFn = Arc Pin + Send>> + Send + Sync>; +pub type CloseDiskFn = Arc Pin + Send>> + Send + Sync>; /// Create a current path updater for tracking scan progress pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) { @@ -506,7 +512,7 @@ pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, let update_fn = { let tracker = Arc::clone(&tracker); - Arc::new(move |path: &str| -> Pin + Send>> { + Arc::new(move |path: &str| -> Pin + Send>> { let tracker = Arc::clone(&tracker); let path = path.to_string(); Box::pin(async move { @@ -517,7 +523,7 @@ pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, let done_fn = { let disk_name = disk_name.clone(); - Arc::new(move || -> Pin + Send>> { + Arc::new(move || -> Pin + Send>> { let disk_name = disk_name.clone(); Box::pin(async move { global_metrics().current_paths.write().await.remove(&disk_name); diff --git a/crates/ecstore/src/metrics_realtime.rs b/crates/ecstore/src/metrics_realtime.rs index 2bbe6456..3e7af4b3 100644 --- a/crates/ecstore/src/metrics_realtime.rs +++ b/crates/ecstore/src/metrics_realtime.rs @@ -112,7 +112,10 @@ pub async fn collect_local_metrics(types: MetricType, opts: &CollectMetricsOpts) if types.contains(&MetricType::SCANNER) { debug!("start get scanner metrics"); - let metrics = global_metrics().report().await; + let mut metrics = global_metrics().report().await; + if let Some(init_time) = rustfs_common::get_global_init_time().await { + metrics.current_started = init_time; + } real_time_metrics.aggregated.scanner = Some(metrics); } diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index 9e571245..939446d7 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -369,6 +369,9 @@ async fn run(opt: config::Opt) -> Result<()> { // 4. Mark as Full Ready now that critical components are warm readiness.mark_stage(SystemStage::FullReady); + // Set the global RustFS initialization time to now + rustfs_common::set_global_init_time_now().await; + // Perform hibernation for 1 second tokio::time::sleep(SHUTDOWN_TIMEOUT).await; // listen to the shutdown signal diff --git a/rustfs/src/server/http.rs b/rustfs/src/server/http.rs index fc6200bc..e255c35e 100644 --- a/rustfs/src/server/http.rs +++ b/rustfs/src/server/http.rs @@ -177,6 +177,9 @@ pub async fn start_http_server( TcpListener::from_std(socket.into())? }; + let tls_acceptor = setup_tls_acceptor(opt.tls_path.as_deref().unwrap_or_default()).await?; + let tls_enabled = tls_acceptor.is_some(); + let protocol = if tls_enabled { "https" } else { "http" }; // Obtain the listener address let local_addr: SocketAddr = listener.local_addr()?; let local_ip = match rustfs_utils::get_local_ip() { @@ -186,11 +189,15 @@ pub async fn start_http_server( local_addr.ip() } }; - let tls_acceptor = setup_tls_acceptor(opt.tls_path.as_deref().unwrap_or_default()).await?; - let tls_enabled = tls_acceptor.is_some(); - let protocol = if tls_enabled { "https" } else { "http" }; + + let local_ip_str = if local_ip.is_ipv6() { + format!("[{local_ip}]") + } else { + local_ip.to_string() + }; + // Detailed endpoint information (showing all API endpoints) - let api_endpoints = format!("{protocol}://{local_ip}:{server_port}"); + let api_endpoints = format!("{protocol}://{local_ip_str}:{server_port}"); let localhost_endpoint = format!("{protocol}://127.0.0.1:{server_port}"); let now_time = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); if opt.console_enable { @@ -198,7 +205,7 @@ pub async fn start_http_server( info!( target: "rustfs::console::startup", - "Console WebUI available at: {protocol}://{local_ip}:{server_port}/rustfs/console/index.html" + "Console WebUI available at: {protocol}://{local_ip_str}:{server_port}/rustfs/console/index.html" ); info!( target: "rustfs::console::startup", @@ -207,7 +214,7 @@ pub async fn start_http_server( ); println!("Console WebUI Start Time: {now_time}"); - println!("Console WebUI available at: {protocol}://{local_ip}:{server_port}/rustfs/console/index.html"); + println!("Console WebUI available at: {protocol}://{local_ip_str}:{server_port}/rustfs/console/index.html"); println!("Console WebUI (localhost): {protocol}://127.0.0.1:{server_port}/rustfs/console/index.html",); } else { info!(target: "rustfs::main::startup","RustFS API: {api_endpoints} {localhost_endpoint}");