use crate::error_handling::ErrorContext;
use crate::metrics::Metrics;
use crate::types::AiLibError;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorThresholds {
pub error_rate_threshold: f64,
pub consecutive_errors: u32,
pub time_window: Duration,
}
impl Default for ErrorThresholds {
fn default() -> Self {
Self {
error_rate_threshold: 0.1, consecutive_errors: 5,
time_window: Duration::from_secs(60),
}
}
}
pub struct ErrorMonitor {
metrics: Arc<dyn Metrics>,
#[allow(dead_code)] alert_thresholds: ErrorThresholds,
}
impl ErrorMonitor {
pub fn new(metrics: Arc<dyn Metrics>, alert_thresholds: ErrorThresholds) -> Self {
Self {
metrics,
alert_thresholds,
}
}
pub async fn record_error(&self, error: &AiLibError, context: &ErrorContext) {
self.metrics.incr_counter("errors.total", 1).await;
self.metrics
.incr_counter(&format!("errors.{}", self.error_type_name(error)), 1)
.await;
if self.should_alert(error, context).await {
self.send_alert(error, context).await;
}
}
async fn should_alert(&self, error: &AiLibError, _context: &ErrorContext) -> bool {
matches!(
error,
AiLibError::RateLimitExceeded(_) | AiLibError::ProviderError(_)
)
}
async fn send_alert(&self, error: &AiLibError, context: &ErrorContext) {
let _ = (error, context);
}
fn error_type_name(&self, error: &AiLibError) -> String {
match error {
AiLibError::RateLimitExceeded(_) => "rate_limit".to_string(),
AiLibError::NetworkError(_) => "network".to_string(),
AiLibError::AuthenticationError(_) => "authentication".to_string(),
AiLibError::ProviderError(_) => "provider".to_string(),
AiLibError::TimeoutError(_) => "timeout".to_string(),
_ => "unknown".to_string(),
}
}
}