rat_quickdns/builder/
metrics.rs1use std::time::{Duration, Instant};
6
7#[derive(Debug, Clone)]
9pub struct PerformanceMetrics {
10 pub total_queries: u64,
12
13 pub successful_queries: u64,
15
16 pub failed_queries: u64,
18
19 pub consecutive_failures: u32,
21
22 pub avg_latency: Duration,
24
25 pub last_success_time: Option<Instant>,
27
28 pub last_failure_time: Option<Instant>,
30
31 pub cdn_accuracy_score: f64,
33}
34
35impl Default for PerformanceMetrics {
36 fn default() -> Self {
37 Self {
38 total_queries: 0,
39 successful_queries: 0,
40 failed_queries: 0,
41 consecutive_failures: 0,
42 avg_latency: Duration::from_millis(100), last_success_time: None,
44 last_failure_time: None,
45 cdn_accuracy_score: 0.8, }
47 }
48}
49
50impl PerformanceMetrics {
51 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn success_rate(&self) -> f64 {
58 if self.total_queries == 0 {
59 0.0
60 } else {
61 self.successful_queries as f64 / self.total_queries as f64
62 }
63 }
64
65 pub fn failure_rate(&self) -> f64 {
67 1.0 - self.success_rate()
68 }
69
70 pub fn is_available(&self) -> bool {
72 self.consecutive_failures < 10
73 }
74
75 pub fn latency_grade(&self) -> &'static str {
77 let ms = self.avg_latency.as_millis();
78 match ms {
79 0..=50 => "优秀",
80 51..=100 => "良好",
81 101..=200 => "一般",
82 201..=500 => "较差",
83 _ => "很差",
84 }
85 }
86
87 pub fn record_success(&mut self, latency: Duration, cdn_accurate: bool) {
89 self.total_queries += 1;
90 self.successful_queries += 1;
91 self.consecutive_failures = 0;
92 self.last_success_time = Some(Instant::now());
93
94 if self.total_queries == 1 {
96 self.avg_latency = latency;
97 } else {
98 let alpha = 0.1; let old_latency_ms = self.avg_latency.as_millis() as f64;
100 let new_latency_ms = latency.as_millis() as f64;
101 let smoothed_latency_ms = old_latency_ms * (1.0 - alpha) + new_latency_ms * alpha;
102 self.avg_latency = Duration::from_millis(smoothed_latency_ms as u64);
103 }
104
105 let current_score = self.cdn_accuracy_score * (self.successful_queries - 1) as f64;
107 let new_score = if cdn_accurate { 1.0 } else { 0.0 };
108 self.cdn_accuracy_score = (current_score + new_score) / self.successful_queries as f64;
109 }
110
111 pub fn record_failure(&mut self) {
113 self.total_queries += 1;
114 self.failed_queries += 1;
115 self.consecutive_failures += 1;
116 self.last_failure_time = Some(Instant::now());
117 }
118
119 pub fn reset(&mut self) {
121 *self = Self::default();
122 }
123
124 pub fn overall_score(&self) -> f64 {
126 let success_weight = 0.4;
127 let latency_weight = 0.3;
128 let cdn_weight = 0.2;
129 let availability_weight = 0.1;
130
131 let success_score = self.success_rate();
132
133 let latency_score = if self.avg_latency.as_millis() > 0 {
134 (1000.0 / (self.avg_latency.as_millis() as f64 + 100.0)).min(1.0)
135 } else {
136 1.0
137 };
138
139 let cdn_score = self.cdn_accuracy_score;
140
141 let availability_score = if self.is_available() { 1.0 } else { 0.0 };
142
143 success_score * success_weight
144 + latency_score * latency_weight
145 + cdn_score * cdn_weight
146 + availability_score * availability_weight
147 }
148}