use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AnalyzerEvent {
Metric {
timestamp: DateTime<Utc>,
name: String,
value: f64,
unit: String,
labels: HashMap<String, String>,
},
Request {
timestamp: DateTime<Utc>,
request_id: String,
model: String,
prompt_tokens: u32,
max_tokens: u32,
temperature: f64,
metadata: HashMap<String, String>,
},
Response {
timestamp: DateTime<Utc>,
request_id: String,
model: String,
completion_tokens: u32,
total_tokens: u32,
latency_ms: u64,
success: bool,
error: Option<String>,
metadata: HashMap<String, String>,
},
Feedback {
timestamp: DateTime<Utc>,
request_id: String,
rating: f64, feedback_type: FeedbackType,
comment: Option<String>,
metadata: HashMap<String, String>,
},
Cost {
timestamp: DateTime<Utc>,
model: String,
tokens: u32,
cost_usd: f64,
metadata: HashMap<String, String>,
},
Alert {
timestamp: DateTime<Utc>,
alert_type: String,
severity: Severity,
message: String,
metadata: HashMap<String, String>,
},
Custom {
timestamp: DateTime<Utc>,
event_type: String,
data: serde_json::Value,
},
}
impl AnalyzerEvent {
pub fn timestamp(&self) -> DateTime<Utc> {
match self {
AnalyzerEvent::Metric { timestamp, .. } => *timestamp,
AnalyzerEvent::Request { timestamp, .. } => *timestamp,
AnalyzerEvent::Response { timestamp, .. } => *timestamp,
AnalyzerEvent::Feedback { timestamp, .. } => *timestamp,
AnalyzerEvent::Cost { timestamp, .. } => *timestamp,
AnalyzerEvent::Alert { timestamp, .. } => *timestamp,
AnalyzerEvent::Custom { timestamp, .. } => *timestamp,
}
}
pub fn metadata(&self) -> Option<&HashMap<String, String>> {
match self {
AnalyzerEvent::Metric { labels, .. } => Some(labels),
AnalyzerEvent::Request { metadata, .. } => Some(metadata),
AnalyzerEvent::Response { metadata, .. } => Some(metadata),
AnalyzerEvent::Feedback { metadata, .. } => Some(metadata),
AnalyzerEvent::Cost { metadata, .. } => Some(metadata),
AnalyzerEvent::Alert { metadata, .. } => Some(metadata),
AnalyzerEvent::Custom { .. } => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FeedbackType {
Positive,
Negative,
Rating,
Quality,
Custom,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Severity {
Info,
Warning,
Error,
Critical,
}
impl Severity {
pub fn is_urgent(&self) -> bool {
matches!(self, Severity::Critical | Severity::Error)
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct Confidence(f64);
impl Confidence {
pub fn new(value: f64) -> Self {
Self(value.clamp(0.0, 1.0))
}
pub fn value(&self) -> f64 {
self.0
}
pub fn is_high(&self) -> bool {
self.0 >= 0.8
}
pub fn is_medium(&self) -> bool {
self.0 >= 0.5 && self.0 < 0.8
}
pub fn is_low(&self) -> bool {
self.0 < 0.5
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Insight {
pub id: String,
pub analyzer: String,
pub timestamp: DateTime<Utc>,
pub severity: Severity,
pub confidence: Confidence,
pub title: String,
pub description: String,
pub category: InsightCategory,
pub evidence: Vec<Evidence>,
pub metrics: HashMap<String, f64>,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum InsightCategory {
Performance,
Cost,
Quality,
Pattern,
Anomaly,
Optimization,
Risk,
General,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Evidence {
pub evidence_type: EvidenceType,
pub description: String,
pub data: serde_json::Value,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EvidenceType {
Statistical,
TimeSeries,
Comparison,
Threshold,
Pattern,
Anomaly,
Feedback,
Historical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Recommendation {
pub id: String,
pub analyzer: String,
pub timestamp: DateTime<Utc>,
pub priority: Priority,
pub title: String,
pub description: String,
pub action: Action,
pub expected_impact: Impact,
pub confidence: Confidence,
pub related_insights: Vec<String>,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Priority {
Low,
Medium,
High,
Urgent,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Action {
pub action_type: ActionType,
pub instructions: String,
pub parameters: HashMap<String, serde_json::Value>,
pub estimated_effort: Option<f64>,
pub risk_level: RiskLevel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ActionType {
ConfigChange,
Scale,
Optimize,
Investigate,
Monitor,
Alert,
Review,
NoAction,
}
impl ActionType {
pub fn to_lowercase(&self) -> String {
match self {
ActionType::ConfigChange => "configchange".to_string(),
ActionType::Scale => "scale".to_string(),
ActionType::Optimize => "optimize".to_string(),
ActionType::Investigate => "investigate".to_string(),
ActionType::Monitor => "monitor".to_string(),
ActionType::Alert => "alert".to_string(),
ActionType::Review => "review".to_string(),
ActionType::NoAction => "noaction".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum RiskLevel {
None,
Low,
Medium,
High,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Impact {
pub performance: Option<ImpactMetric>,
pub cost: Option<ImpactMetric>,
pub quality: Option<ImpactMetric>,
pub description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImpactMetric {
pub name: String,
pub current: f64,
pub expected: f64,
pub unit: String,
pub improvement_pct: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Alert {
pub id: String,
pub analyzer: String,
pub timestamp: DateTime<Utc>,
pub severity: Severity,
pub title: String,
pub message: String,
pub status: AlertStatus,
pub threshold: Option<Threshold>,
pub related_insights: Vec<String>,
pub tags: Vec<String>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlertStatus {
Firing,
Resolved,
Acknowledged,
Silenced,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Threshold {
pub metric: String,
pub value: f64,
pub operator: ThresholdOperator,
pub duration: Duration,
pub actual_value: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ThresholdOperator {
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Equal,
NotEqual,
}
impl ThresholdOperator {
pub fn compare(&self, actual: f64, threshold: f64) -> bool {
match self {
ThresholdOperator::GreaterThan => actual > threshold,
ThresholdOperator::GreaterThanOrEqual => actual >= threshold,
ThresholdOperator::LessThan => actual < threshold,
ThresholdOperator::LessThanOrEqual => actual <= threshold,
ThresholdOperator::Equal => (actual - threshold).abs() < f64::EPSILON,
ThresholdOperator::NotEqual => (actual - threshold).abs() >= f64::EPSILON,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalysisReport {
pub analyzer: String,
pub timestamp: DateTime<Utc>,
pub period_start: DateTime<Utc>,
pub period_end: DateTime<Utc>,
pub summary: ReportSummary,
pub insights: Vec<Insight>,
pub recommendations: Vec<Recommendation>,
pub alerts: Vec<Alert>,
pub metrics: HashMap<String, f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSummary {
pub events_processed: u64,
pub events_per_second: f64,
pub insights_count: u64,
pub recommendations_count: u64,
pub alerts_count: u64,
pub analysis_duration_ms: u64,
pub highlights: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalyzerStats {
pub analyzer: String,
pub events_processed: u64,
pub events_dropped: u64,
pub insights_generated: u64,
pub recommendations_generated: u64,
pub alerts_triggered: u64,
pub analysis_time_ms: u64,
pub avg_analysis_time_us: f64,
pub memory_usage_bytes: usize,
pub error_count: u64,
pub last_error: Option<String>,
pub uptime_seconds: u64,
}
impl Default for AnalyzerStats {
fn default() -> Self {
Self {
analyzer: String::new(),
events_processed: 0,
events_dropped: 0,
insights_generated: 0,
recommendations_generated: 0,
alerts_triggered: 0,
analysis_time_ms: 0,
avg_analysis_time_us: 0.0,
memory_usage_bytes: 0,
error_count: 0,
last_error: None,
uptime_seconds: 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_confidence_creation() {
let conf = Confidence::new(0.75);
assert_eq!(conf.value(), 0.75);
assert!(conf.is_medium());
let conf = Confidence::new(1.5); assert_eq!(conf.value(), 1.0);
let conf = Confidence::new(-0.5); assert_eq!(conf.value(), 0.0);
}
#[test]
fn test_confidence_levels() {
assert!(Confidence::new(0.9).is_high());
assert!(!Confidence::new(0.9).is_medium());
assert!(!Confidence::new(0.9).is_low());
assert!(Confidence::new(0.6).is_medium());
assert!(!Confidence::new(0.6).is_high());
assert!(!Confidence::new(0.6).is_low());
assert!(Confidence::new(0.3).is_low());
assert!(!Confidence::new(0.3).is_medium());
assert!(!Confidence::new(0.3).is_high());
}
#[test]
fn test_severity_is_urgent() {
assert!(!Severity::Info.is_urgent());
assert!(!Severity::Warning.is_urgent());
assert!(Severity::Error.is_urgent());
assert!(Severity::Critical.is_urgent());
}
#[test]
fn test_threshold_operator_compare() {
assert!(ThresholdOperator::GreaterThan.compare(10.0, 5.0));
assert!(!ThresholdOperator::GreaterThan.compare(5.0, 10.0));
assert!(ThresholdOperator::LessThan.compare(5.0, 10.0));
assert!(!ThresholdOperator::LessThan.compare(10.0, 5.0));
assert!(ThresholdOperator::Equal.compare(5.0, 5.0));
assert!(!ThresholdOperator::Equal.compare(5.0, 6.0));
}
#[test]
fn test_analyzer_event_timestamp() {
let now = Utc::now();
let event = AnalyzerEvent::Metric {
timestamp: now,
name: "test".to_string(),
value: 1.0,
unit: "ms".to_string(),
labels: HashMap::new(),
};
assert_eq!(event.timestamp(), now);
}
}