pub mod metrics;
pub mod alerts;
pub mod health;
pub mod config;
pub use metrics::{
Metric, TimeRange, AggregationType, AggregatedMetric, MetricsCollector, MetricsConfig,
};
pub use alerts::{
AlertRule, AlertCondition, ComparisonOperator, AlertSeverity, Alert, AlertManager,
AlertStats, AlertConfig,
};
pub use health::{
HealthCheck, HealthStatus, SystemStatus, HealthCheckResult, HealthReporter, HealthStats,
HealthConfig,
};
pub use config::{
MonitorConfig, MonitoringStats, PerformanceConfig, ResourceConfig, ExtendedMonitorConfig,
};
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug, Clone)]
pub struct ReliabilityMonitor {
pub metrics_collector: MetricsCollector,
pub alert_manager: AlertManager,
pub health_reporter: HealthReporter,
pub stats: Arc<RwLock<MonitoringStats>>,
pub initialized: bool,
}
impl ReliabilityMonitor {
pub fn new() -> Self {
Self {
metrics_collector: MetricsCollector::new(),
alert_manager: AlertManager::new(),
health_reporter: HealthReporter::new(),
stats: Arc::new(RwLock::new(MonitoringStats::new())),
initialized: false,
}
}
pub fn with_config(config: MonitorConfig) -> Self {
Self {
metrics_collector: MetricsCollector::with_config(config.metrics_config),
alert_manager: AlertManager::with_config(config.alert_config),
health_reporter: HealthReporter::with_config(config.health_config),
stats: Arc::new(RwLock::new(MonitoringStats::new())),
initialized: false,
}
}
pub async fn initialize(&mut self) -> Result<(), String> {
if self.initialized {
return Err("Monitoring system is already initialized".to_string());
}
self.metrics_collector = MetricsCollector::new();
self.alert_manager = AlertManager::new();
self.health_reporter = HealthReporter::new();
self.initialized = true;
Ok(())
}
pub fn record_metric(&mut self, metric: Metric) {
if !self.initialized {
return;
}
self.metrics_collector.record(metric.clone());
let alerts = self.alert_manager.check_metric(&metric.name, metric.value);
if let Ok(mut stats) = self.stats.try_write() {
stats.increment_metrics_collected();
if !alerts.is_empty() {
stats.increment_alerts_triggered();
}
}
}
pub fn add_alert_rule(&mut self, rule: AlertRule) {
if !self.initialized {
return;
}
self.alert_manager.add_rule(rule);
}
pub fn add_health_check(&mut self, health_check: HealthCheck) {
if !self.initialized {
return;
}
self.health_reporter.add_health_check(health_check);
}
pub fn perform_health_checks(&mut self) -> Vec<HealthCheckResult> {
if !self.initialized {
return Vec::new();
}
let results = self.health_reporter.perform_all_health_checks();
if let Ok(mut stats) = self.stats.try_write() {
stats.increment_health_checks();
}
results
}
pub fn get_system_status(&mut self) -> SystemStatus {
if !self.initialized {
return SystemStatus::new();
}
self.health_reporter.get_current_system_status()
}
pub async fn get_stats(&self) -> Result<MonitoringStats, String> {
if !self.initialized {
return Err("Monitoring system is not initialized".to_string());
}
let stats = self.stats.read().await;
Ok(stats.clone())
}
pub fn get_alert_stats(&self) -> AlertStats {
if !self.initialized {
return AlertStats {
total_rules: 0,
active_alerts: 0,
critical_alerts: 0,
high_alerts: 0,
medium_alerts: 0,
low_alerts: 0,
total_history: 0,
};
}
self.alert_manager.get_stats()
}
pub fn get_health_stats(&self) -> HealthStats {
if !self.initialized {
return HealthStats {
total_checks: 0,
healthy_checks: 0,
degraded_checks: 0,
unhealthy_checks: 0,
unknown_checks: 0,
overall_status: HealthStatus::Unknown,
uptime_seconds: 0,
};
}
self.health_reporter.get_health_stats()
}
pub fn get_metrics(&self, name: &str, time_range: &TimeRange) -> Vec<&Metric> {
if !self.initialized {
return Vec::new();
}
self.metrics_collector.get_metrics(name, time_range)
}
pub fn get_aggregated_metrics(
&self,
name: &str,
time_range: &TimeRange,
aggregation_type: AggregationType,
) -> Option<AggregatedMetric> {
if !self.initialized {
return None;
}
self.metrics_collector.aggregate_metrics(name, time_range, aggregation_type)
}
pub fn get_active_alerts(&self) -> Vec<&Alert> {
if !self.initialized {
return Vec::new();
}
self.alert_manager.get_active_alerts()
}
pub fn resolve_alert(&mut self, alert_id: &str) -> bool {
if !self.initialized {
return false;
}
self.alert_manager.resolve_alert(alert_id)
}
pub fn get_metric_names(&self) -> Vec<String> {
if !self.initialized {
return Vec::new();
}
self.metrics_collector.get_metric_names()
}
pub fn clear_metrics(&mut self) {
if !self.initialized {
return;
}
self.metrics_collector.clear();
}
pub fn clear_alert_history(&mut self) {
if !self.initialized {
return;
}
self.alert_manager.clear_history();
}
pub async fn shutdown(&mut self) -> Result<(), String> {
if !self.initialized {
return Err("Monitoring system is not initialized".to_string());
}
self.perform_health_checks();
self.clear_metrics();
self.clear_alert_history();
self.initialized = false;
Ok(())
}
}
impl Default for ReliabilityMonitor {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn test_reliability_monitor_creation() {
let monitor = ReliabilityMonitor::new();
assert!(!monitor.initialized);
}
#[test]
fn test_reliability_monitor_with_config() {
let config = MonitorConfig::new();
let monitor = ReliabilityMonitor::with_config(config);
assert!(!monitor.initialized);
}
#[tokio::test]
async fn test_reliability_monitor_initialization() {
let mut monitor = ReliabilityMonitor::new();
assert!(!monitor.initialized);
let result = monitor.initialize().await;
assert!(result.is_ok());
assert!(monitor.initialized);
let result = monitor.initialize().await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_reliability_monitor_operations() {
let mut monitor = ReliabilityMonitor::new();
let metric = Metric::new("test_metric".to_string(), 42.0);
monitor.record_metric(metric);
let metrics = monitor.get_metrics("test_metric", &TimeRange::last_seconds(3600));
assert!(metrics.is_empty());
let result = monitor.initialize();
assert!(result.await.is_ok());
let metric = Metric::new("test_metric".to_string(), 42.0);
monitor.record_metric(metric);
let metrics = monitor.get_metrics("test_metric", &TimeRange::last_seconds(3600));
assert_eq!(metrics.len(), 1);
assert_eq!(metrics[0].value, 42.0);
}
#[tokio::test]
async fn test_reliability_monitor_alert_integration() {
let mut monitor = ReliabilityMonitor::new();
monitor.initialize().await.unwrap();
let condition = AlertCondition::new(ComparisonOperator::GreaterThan, 80.0, 60);
let rule = AlertRule::new(
"cpu_high".to_string(),
"High CPU Usage".to_string(),
"cpu_usage".to_string(),
condition,
AlertSeverity::High,
);
monitor.add_alert_rule(rule);
let metric = Metric::new("cpu_usage".to_string(), 85.0);
monitor.record_metric(metric);
let active_alerts = monitor.get_active_alerts();
assert_eq!(active_alerts.len(), 1);
assert_eq!(active_alerts[0].severity, AlertSeverity::High);
}
#[tokio::test]
async fn test_reliability_monitor_health_integration() {
let mut monitor = ReliabilityMonitor::new();
monitor.initialize().await.unwrap();
let health_check = HealthCheck::new(
"database".to_string(),
"Database Health".to_string(),
"Checks database connectivity".to_string(),
"check_database".to_string(),
);
monitor.add_health_check(health_check);
let results = monitor.perform_health_checks();
assert_eq!(results.len(), 1);
assert_eq!(results[0].check_id, "database");
let status = monitor.get_system_status();
assert!(status.uptime_seconds > 0);
}
#[tokio::test]
async fn test_reliability_monitor_statistics() {
let mut monitor = ReliabilityMonitor::new();
monitor.initialize().await.unwrap();
monitor.record_metric(Metric::new("metric1".to_string(), 10.0));
monitor.record_metric(Metric::new("metric2".to_string(), 20.0));
let alert_stats = monitor.get_alert_stats();
let health_stats = monitor.get_health_stats();
assert_eq!(alert_stats.total_rules, 0);
assert_eq!(health_stats.total_checks, 0);
let metric_names = monitor.get_metric_names();
assert_eq!(metric_names.len(), 2);
assert!(metric_names.contains(&"metric1".to_string()));
assert!(metric_names.contains(&"metric2".to_string()));
}
#[tokio::test]
async fn test_reliability_monitor_shutdown() {
let mut monitor = ReliabilityMonitor::new();
monitor.initialize().await.unwrap();
assert!(monitor.initialized);
let result = monitor.shutdown().await;
assert!(result.is_ok());
assert!(!monitor.initialized);
let result = monitor.shutdown().await;
assert!(result.is_err());
}
}