use crate::utils::current_timestamp;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::sync::Mutex;
use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMetrics {
pub network: NetworkMetrics,
pub storage: StorageMetrics,
pub rpc: RpcMetrics,
pub performance: PerformanceMetrics,
pub system: SystemMetrics,
pub timestamp: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NetworkMetrics {
pub peer_count: usize,
pub bytes_sent: u64,
pub bytes_received: u64,
pub messages_sent: u64,
pub messages_received: u64,
pub active_connections: usize,
pub banned_peers: usize,
pub connection_attempts: u64,
pub connection_failures: u64,
pub dos_protection: DosMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DosMetrics {
pub connection_rate_violations: u64,
pub auto_bans: u64,
pub message_queue_overflows: u64,
pub active_connection_limit_hits: u64,
pub resource_exhaustion_events: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct StorageMetrics {
pub block_count: usize,
pub utxo_count: usize,
pub transaction_count: usize,
pub disk_size: u64,
pub within_bounds: bool,
pub pruning: Option<PruningMetrics>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PruningMetrics {
pub blocks_pruned: u64,
pub blocks_kept: u64,
pub storage_freed: u64,
pub last_prune_height: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RpcMetrics {
pub requests_total: u64,
pub requests_success: u64,
pub requests_failed: u64,
pub requests_per_second: f64,
pub avg_response_time_ms: f64,
pub active_connections: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PerformanceMetrics {
pub avg_block_processing_time_ms: f64,
pub avg_tx_validation_time_ms: f64,
pub blocks_per_second: f64,
pub transactions_per_second: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SystemMetrics {
pub uptime_seconds: u64,
pub memory_usage_bytes: Option<u64>,
pub cpu_usage_percent: Option<f64>,
}
pub struct MetricsCollector {
network: Arc<Mutex<NetworkMetrics>>,
storage: Arc<Mutex<StorageMetrics>>,
rpc: Arc<Mutex<RpcMetrics>>,
performance: Arc<Mutex<PerformanceMetrics>>,
system: Arc<Mutex<SystemMetrics>>,
start_time: SystemTime,
}
impl MetricsCollector {
pub fn new() -> Self {
Self {
network: Arc::new(Mutex::new(NetworkMetrics::default())),
storage: Arc::new(Mutex::new(StorageMetrics::default())),
rpc: Arc::new(Mutex::new(RpcMetrics::default())),
performance: Arc::new(Mutex::new(PerformanceMetrics::default())),
system: Arc::new(Mutex::new(SystemMetrics::default())),
start_time: SystemTime::now(),
}
}
pub fn collect(&self) -> NodeMetrics {
let timestamp = current_timestamp();
let uptime = SystemTime::now()
.duration_since(self.start_time)
.unwrap_or_else(|_| {
tracing::warn!("System clock went backward, using 0 for uptime");
std::time::Duration::from_secs(0)
})
.as_secs();
let mut system = self.system.lock().unwrap();
system.uptime_seconds = uptime;
NodeMetrics {
network: self.network.lock().unwrap().clone(),
storage: self.storage.lock().unwrap().clone(),
rpc: self.rpc.lock().unwrap().clone(),
performance: self.performance.lock().unwrap().clone(),
system: system.clone(),
timestamp,
}
}
pub fn update_network<F>(&self, f: F)
where
F: FnOnce(&mut NetworkMetrics),
{
let mut metrics = self.network.lock().unwrap();
f(&mut metrics);
}
pub fn update_storage<F>(&self, f: F)
where
F: FnOnce(&mut StorageMetrics),
{
let mut metrics = self.storage.lock().unwrap();
f(&mut metrics);
}
pub fn update_rpc<F>(&self, f: F)
where
F: FnOnce(&mut RpcMetrics),
{
let mut metrics = self.rpc.lock().unwrap();
f(&mut metrics);
}
pub fn update_performance<F>(&self, f: F)
where
F: FnOnce(&mut PerformanceMetrics),
{
let mut metrics = self.performance.lock().unwrap();
f(&mut metrics);
}
pub fn network(&self) -> Arc<Mutex<NetworkMetrics>> {
Arc::clone(&self.network)
}
pub fn storage(&self) -> Arc<Mutex<StorageMetrics>> {
Arc::clone(&self.storage)
}
pub fn rpc(&self) -> Arc<Mutex<RpcMetrics>> {
Arc::clone(&self.rpc)
}
pub fn performance(&self) -> Arc<Mutex<PerformanceMetrics>> {
Arc::clone(&self.performance)
}
}
impl Default for MetricsCollector {
fn default() -> Self {
Self::new()
}
}