- Remove all unused configuration options from dashboard config module - Eliminate hardcoded defaults - dashboard now requires config file like agent - Keep only actually used config: zmq.subscriber_ports and hosts.predefined_hosts - Remove unused get_host_metrics function from metric store - Clean up missing module imports (hosts, utils) - Make dashboard fail fast if no configuration provided - Align dashboard config approach with agent configuration pattern
128 lines
4.1 KiB
Rust
128 lines
4.1 KiB
Rust
use cm_dashboard_shared::Metric;
|
|
use std::collections::HashMap;
|
|
use std::time::{Duration, Instant};
|
|
use tracing::{debug, info, warn};
|
|
|
|
use super::MetricDataPoint;
|
|
|
|
/// Central metric storage for the dashboard
|
|
pub struct MetricStore {
|
|
/// Current metrics: hostname -> metric_name -> metric
|
|
current_metrics: HashMap<String, HashMap<String, Metric>>,
|
|
/// Historical metrics for trending
|
|
historical_metrics: HashMap<String, Vec<MetricDataPoint>>,
|
|
/// Last update timestamp per host
|
|
last_update: HashMap<String, Instant>,
|
|
/// Configuration
|
|
max_metrics_per_host: usize,
|
|
history_retention: Duration,
|
|
}
|
|
|
|
impl MetricStore {
|
|
pub fn new(max_metrics_per_host: usize, history_retention_hours: u64) -> Self {
|
|
Self {
|
|
current_metrics: HashMap::new(),
|
|
historical_metrics: HashMap::new(),
|
|
last_update: HashMap::new(),
|
|
max_metrics_per_host,
|
|
history_retention: Duration::from_secs(history_retention_hours * 3600),
|
|
}
|
|
}
|
|
|
|
/// Update metrics for a specific host
|
|
pub fn update_metrics(&mut self, hostname: &str, metrics: Vec<Metric>) {
|
|
let now = Instant::now();
|
|
|
|
debug!("Updating {} metrics for host {}", metrics.len(), hostname);
|
|
|
|
// Get or create host entry
|
|
let host_metrics = self
|
|
.current_metrics
|
|
.entry(hostname.to_string())
|
|
.or_insert_with(HashMap::new);
|
|
|
|
// Get or create historical entry
|
|
let host_history = self
|
|
.historical_metrics
|
|
.entry(hostname.to_string())
|
|
.or_insert_with(Vec::new);
|
|
|
|
// Update current metrics and add to history
|
|
for metric in metrics {
|
|
let metric_name = metric.name.clone();
|
|
|
|
// Store current metric
|
|
host_metrics.insert(metric_name.clone(), metric.clone());
|
|
|
|
// Add to history
|
|
host_history.push(MetricDataPoint { received_at: now });
|
|
}
|
|
|
|
// Update last update timestamp
|
|
self.last_update.insert(hostname.to_string(), now);
|
|
|
|
// Get metrics count before cleanup
|
|
let metrics_count = host_metrics.len();
|
|
|
|
// Cleanup old history and enforce limits
|
|
self.cleanup_host_data(hostname);
|
|
|
|
info!(
|
|
"Updated metrics for {}: {} current metrics",
|
|
hostname, metrics_count
|
|
);
|
|
}
|
|
|
|
/// Get current metric for a specific host
|
|
pub fn get_metric(&self, hostname: &str, metric_name: &str) -> Option<&Metric> {
|
|
self.current_metrics.get(hostname)?.get(metric_name)
|
|
}
|
|
|
|
|
|
/// Get all current metrics for a host as a vector
|
|
pub fn get_metrics_for_host(&self, hostname: &str) -> Vec<&Metric> {
|
|
if let Some(metrics_map) = self.current_metrics.get(hostname) {
|
|
metrics_map.values().collect()
|
|
} else {
|
|
Vec::new()
|
|
}
|
|
}
|
|
|
|
/// Get connected hosts (hosts with recent updates)
|
|
pub fn get_connected_hosts(&self, timeout: Duration) -> Vec<String> {
|
|
let now = Instant::now();
|
|
|
|
self.last_update
|
|
.iter()
|
|
.filter_map(|(hostname, &last_update)| {
|
|
if now.duration_since(last_update) <= timeout {
|
|
Some(hostname.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
/// Cleanup old data and enforce limits
|
|
fn cleanup_host_data(&mut self, hostname: &str) {
|
|
let now = Instant::now();
|
|
|
|
// Cleanup historical data
|
|
if let Some(history) = self.historical_metrics.get_mut(hostname) {
|
|
// Remove old entries
|
|
history.retain(|dp| now.duration_since(dp.received_at) <= self.history_retention);
|
|
|
|
// Enforce size limit
|
|
if history.len() > self.max_metrics_per_host {
|
|
let excess = history.len() - self.max_metrics_per_host;
|
|
history.drain(0..excess);
|
|
warn!(
|
|
"Trimmed {} old metrics for host {} (size limit: {})",
|
|
excess, hostname, self.max_metrics_per_host
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|