mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-11-13 07:25:13 +00:00
feat: Remove system statistics and health check methods from monitoring module and update Redis connection handling
- Remove get_system_statistics/get_uptime/health_check/get_memory_usage/get_process_memory/estimate_memory_usage/get_redis_memory_usage methods from ChargingEngine impl - Remove SystemStats/HealthStatus struct definitions - Update get_performance_metrics/calculate_rps/calculate_avg_response_time/get_error_statistics/get_last_error/get_redis_latency to use get_multiplexed_async_connection instead of get_async_connection - Replace context error handling with map
This commit is contained in:
@@ -4,124 +4,10 @@ use std::time::SystemTime;
|
|||||||
use crate::errors::{ChargingError, ChargingResult, ErrorContext};
|
use crate::errors::{ChargingError, ChargingResult, ErrorContext};
|
||||||
use super::types::{SystemStats, HealthStatus};
|
use super::types::{SystemStats, HealthStatus};
|
||||||
|
|
||||||
impl super::ChargingEngine {
|
impl crate::charging::ChargingEngine {
|
||||||
pub async fn get_system_statistics(&self) -> ChargingResult<SystemStats> {
|
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
|
||||||
.context("Failed to get Redis connection")?;
|
|
||||||
|
|
||||||
let active_sessions: u64 = conn.get("stats:active_sessions").await.unwrap_or(0);
|
|
||||||
let total_accounts: u64 = conn.keys("account:*").await.unwrap_or_default().len() as u64;
|
|
||||||
let blocked_users: u64 = conn.keys("block:*").await.unwrap_or_default().len() as u64;
|
|
||||||
let low_balance_alerts: u64 = conn.keys("alert:low_balance:*").await.unwrap_or_default().len() as u64;
|
|
||||||
|
|
||||||
let stats = SystemStats {
|
|
||||||
active_sessions,
|
|
||||||
total_accounts,
|
|
||||||
blocked_users,
|
|
||||||
low_balance_alerts,
|
|
||||||
uptime: self.get_uptime().await?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(stats)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_uptime(&self) -> ChargingResult<u64> {
|
|
||||||
// Calculate actual uptime since startup
|
|
||||||
match self.startup_time.elapsed() {
|
|
||||||
Ok(duration) => Ok(duration.as_secs()),
|
|
||||||
Err(_) => {
|
|
||||||
// If system time went backwards, fallback to current time
|
|
||||||
Ok(SystemTime::now()
|
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.as_secs())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn health_check(&self) -> ChargingResult<HealthStatus> {
|
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
|
||||||
.context("Failed to get Redis connection")?;
|
|
||||||
|
|
||||||
// Test Redis connection
|
|
||||||
let _: String = conn.get("health_check").await.unwrap_or_else(|_| "ok".to_string());
|
|
||||||
|
|
||||||
let status = HealthStatus {
|
|
||||||
redis_connected: true,
|
|
||||||
active_sync: true,
|
|
||||||
last_sync: chrono::Utc::now(),
|
|
||||||
memory_usage: self.get_memory_usage().await?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_memory_usage(&self) -> ChargingResult<u64> {
|
|
||||||
// Get actual memory usage from system
|
|
||||||
match self.get_process_memory() {
|
|
||||||
Ok(memory_bytes) => Ok(memory_bytes),
|
|
||||||
Err(_) => {
|
|
||||||
// Fallback to Redis memory usage if system memory fails
|
|
||||||
self.get_redis_memory_usage().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_process_memory(&self) -> ChargingResult<u64> {
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Try to read from /proc/self/status for Linux systems
|
|
||||||
if let Ok(status) = fs::read_to_string("/proc/self/status") {
|
|
||||||
for line in status.lines() {
|
|
||||||
if line.starts_with("VmRSS:") {
|
|
||||||
if let Some(memory_str) = line.split_whitespace().nth(1) {
|
|
||||||
if let Ok(memory_kb) = memory_str.parse::<u64>() {
|
|
||||||
return Ok(memory_kb * 1024); // Convert KB to bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback for non-Linux systems or if reading fails
|
|
||||||
self.estimate_memory_usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn estimate_memory_usage(&self) -> ChargingResult<u64> {
|
|
||||||
// Estimate memory usage based on known structures
|
|
||||||
// This is a rough estimate for non-Linux systems
|
|
||||||
let base_memory = 20_000_000; // 20MB base
|
|
||||||
let redis_connections = 5_000_000; // 5MB per connection estimate
|
|
||||||
let session_data = 10_000_000; // 10MB for session data
|
|
||||||
|
|
||||||
Ok(base_memory + redis_connections + session_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_redis_memory_usage(&self) -> ChargingResult<u64> {
|
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
|
||||||
.context("Failed to get Redis connection")?;
|
|
||||||
|
|
||||||
// Get Redis memory info
|
|
||||||
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
|
||||||
|
|
||||||
// Parse memory usage from Redis info
|
|
||||||
for line in info.lines() {
|
|
||||||
if line.starts_with("used_memory:") {
|
|
||||||
if let Some(memory_str) = line.split(':').nth(1) {
|
|
||||||
if let Ok(memory_bytes) = memory_str.parse::<u64>() {
|
|
||||||
return Ok(memory_bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to estimate
|
|
||||||
self.estimate_memory_usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_performance_metrics(&self) -> ChargingResult<PerformanceMetrics> {
|
pub async fn get_performance_metrics(&self) -> ChargingResult<PerformanceMetrics> {
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
let mut conn = self.redis_client.get_multiplexed_async_connection().await
|
||||||
.context("Failed to get Redis connection")?;
|
.map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?;
|
||||||
|
|
||||||
// Get Redis info
|
// Get Redis info
|
||||||
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
||||||
@@ -151,8 +37,8 @@ impl super::ChargingEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn calculate_rps(&self) -> ChargingResult<f64> {
|
async fn calculate_rps(&self) -> ChargingResult<f64> {
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
let mut conn = self.redis_client.get_multiplexed_async_connection().await
|
||||||
.context("Failed to get Redis connection")?;
|
.map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?;
|
||||||
|
|
||||||
// Get Redis instantaneous ops per second
|
// Get Redis instantaneous ops per second
|
||||||
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
let info: String = redis::cmd("INFO").query_async(&mut conn).await.unwrap_or_default();
|
||||||
@@ -179,17 +65,17 @@ impl super::ChargingEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn calculate_avg_response_time(&self) -> ChargingResult<f64> {
|
async fn calculate_avg_response_time(&self) -> ChargingResult<f64> {
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
let mut conn = self.redis_client.get_multiplexed_async_connection().await
|
||||||
.context("Failed to get Redis connection")?;
|
.map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?;
|
||||||
|
|
||||||
// Track response times in Redis for calculation
|
// Track response times in Redis for calculation
|
||||||
let response_times_key = "metrics:response_times";
|
let response_times_key = "metrics:response_times";
|
||||||
|
|
||||||
// Get recent response times (last 100 operations)
|
// Get recent response times (last 100 operations)
|
||||||
let response_times: Vec<f64> = conn
|
let response_times_raw: Vec<String> = redis::AsyncCommands::lrange(&mut conn, response_times_key, 0, 99)
|
||||||
.lrange(response_times_key, 0, 99)
|
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default();
|
||||||
|
let response_times: Vec<f64> = response_times_raw
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|s| s.parse::<f64>().ok())
|
.filter_map(|s| s.parse::<f64>().ok())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -205,7 +91,7 @@ impl super::ChargingEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_redis_latency(&self, conn: &mut redis::aio::Connection) -> ChargingResult<f64> {
|
async fn get_redis_latency(&self, conn: &mut redis::aio::MultiplexedConnection) -> ChargingResult<f64> {
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
// Measure Redis ping latency
|
// Measure Redis ping latency
|
||||||
@@ -217,18 +103,18 @@ impl super::ChargingEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_error_statistics(&self) -> ChargingResult<ErrorStats> {
|
pub async fn get_error_statistics(&self) -> ChargingResult<ErrorStats> {
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
let mut conn = self.redis_client.get_multiplexed_async_connection().await
|
||||||
.context("Failed to get Redis connection")?;
|
.map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?;
|
||||||
|
|
||||||
let pattern = "error:*".to_string();
|
let pattern = "error:*".to_string();
|
||||||
let keys: Vec<String> = conn.keys(&pattern).await
|
let keys: Vec<String> = redis::AsyncCommands::keys(&mut conn, &pattern).await
|
||||||
.context("Failed to get error keys")?;
|
.map_err(|e| crate::errors::ChargingError::RedisOperation(e.to_string()))?;
|
||||||
|
|
||||||
let mut total_errors = 0u64;
|
let mut total_errors = 0u64;
|
||||||
let mut error_types = std::collections::HashMap::new();
|
let mut error_types = std::collections::HashMap::new();
|
||||||
|
|
||||||
for key in keys {
|
for key in keys {
|
||||||
if let Ok(count) = conn.get::<_, u64>(&key).await {
|
if let Ok(count) = redis::AsyncCommands::get::<_, u64>(&mut conn, &key).await {
|
||||||
total_errors += count;
|
total_errors += count;
|
||||||
|
|
||||||
let error_type = key.split(':').nth(1).unwrap_or("unknown");
|
let error_type = key.split(':').nth(1).unwrap_or("unknown");
|
||||||
@@ -246,30 +132,14 @@ impl super::ChargingEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_last_error(&self) -> ChargingResult<Option<String>> {
|
async fn get_last_error(&self) -> ChargingResult<Option<String>> {
|
||||||
let mut conn = self.redis_client.get_async_connection().await
|
let mut conn = self.redis_client.get_multiplexed_async_connection().await
|
||||||
.context("Failed to get Redis connection")?;
|
.map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?;
|
||||||
|
|
||||||
let last_error: Option<String> = conn.get("last_error").await.unwrap_or(None);
|
let last_error: Option<String> = redis::AsyncCommands::get(&mut conn, "last_error").await.unwrap_or(None);
|
||||||
Ok(last_error)
|
Ok(last_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SystemStats {
|
|
||||||
pub active_sessions: u64,
|
|
||||||
pub total_accounts: u64,
|
|
||||||
pub blocked_users: u64,
|
|
||||||
pub low_balance_alerts: u64,
|
|
||||||
pub uptime: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct HealthStatus {
|
|
||||||
pub redis_connected: bool,
|
|
||||||
pub active_sync: bool,
|
|
||||||
pub last_sync: chrono::DateTime<chrono::Utc>,
|
|
||||||
pub memory_usage: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PerformanceMetrics {
|
pub struct PerformanceMetrics {
|
||||||
|
|||||||
Reference in New Issue
Block a user