1use crate::core::error::{ErrorKind, ErrorSeverity, MemScopeError};
2use std::collections::HashMap;
3use std::sync::atomic::{AtomicUsize, Ordering};
4use std::sync::{Arc, Mutex};
5use tracing::error;
6
7type ErrorHandlerFn = Box<dyn Fn(&MemScopeError) + Send + Sync>;
9
10pub struct ErrorHandler {
12 error_counts: HashMap<ErrorKind, AtomicUsize>,
14 recent_errors: Arc<Mutex<Vec<MemScopeError>>>,
16 max_recent_errors: usize,
18 reporter: ErrorReporter,
20}
21
22pub struct ErrorReporter {
24 log_to_stderr: bool,
26 store_errors: bool,
28 min_severity: ErrorSeverity,
30 custom_handlers: HashMap<ErrorSeverity, ErrorHandlerFn>,
32}
33
34impl ErrorHandler {
35 pub fn new() -> Self {
37 Self {
38 error_counts: HashMap::new(),
39 recent_errors: Arc::new(Mutex::new(Vec::new())),
40 max_recent_errors: 100,
41 reporter: ErrorReporter::new(),
42 }
43 }
44
45 pub fn with_config(max_recent_errors: usize, reporter: ErrorReporter) -> Self {
47 Self {
48 error_counts: HashMap::new(),
49 recent_errors: Arc::new(Mutex::new(Vec::new())),
50 max_recent_errors,
51 reporter,
52 }
53 }
54
55 pub fn handle_error(&mut self, error: MemScopeError) -> ErrorResponse {
57 self.update_statistics(&error);
59
60 if self.reporter.store_errors {
62 self.store_recent_error(error.clone());
63 }
64
65 let reported = self.reporter.report_error(&error);
67
68 let response = self.determine_response(&error);
70
71 if reported && response.should_log() {
72 self.log_response(&error, &response);
73 }
74
75 response
76 }
77
78 pub fn get_error_counts(&self) -> HashMap<ErrorKind, usize> {
80 self.error_counts
81 .iter()
82 .map(|(kind, count)| (*kind, count.load(Ordering::Relaxed)))
83 .collect()
84 }
85
86 pub fn get_recent_errors(&self) -> Vec<MemScopeError> {
88 self.recent_errors
89 .lock()
90 .map(|errors| errors.clone())
91 .unwrap_or_default()
92 }
93
94 pub fn clear_statistics(&mut self) {
96 for count in self.error_counts.values() {
97 count.store(0, Ordering::Relaxed);
98 }
99
100 if let Ok(mut recent) = self.recent_errors.lock() {
101 recent.clear();
102 }
103 }
104
105 pub fn get_error_frequency(&self) -> ErrorFrequencyAnalysis {
107 let counts = self.get_error_counts();
108 let total_errors: usize = counts.values().sum();
109
110 let most_common = counts
111 .iter()
112 .max_by_key(|(_, count)| *count)
113 .map(|(kind, count)| (*kind, *count));
114
115 let error_rate = if let Ok(recent) = self.recent_errors.lock() {
116 if recent.is_empty() {
117 0.0
118 } else {
119 let oldest_time = recent.first().map(|e| e.context().timestamp);
120 let newest_time = recent.last().map(|e| e.context().timestamp);
121
122 if let (Some(oldest), Some(newest)) = (oldest_time, newest_time) {
123 match newest.duration_since(oldest) {
124 Ok(duration) => {
125 let duration_secs = duration.as_secs_f64();
126 if duration_secs > 0.0 {
127 recent.len() as f64 / duration_secs
128 } else {
129 0.0
130 }
131 }
132 Err(_) => 0.0,
133 }
134 } else {
135 0.0
136 }
137 }
138 } else {
139 0.0
140 };
141
142 ErrorFrequencyAnalysis {
143 total_errors,
144 most_common_error: most_common,
145 errors_per_second: error_rate,
146 error_distribution: counts,
147 }
148 }
149
150 fn update_statistics(&mut self, error: &MemScopeError) {
151 let counter = self
152 .error_counts
153 .entry(error.kind())
154 .or_insert_with(|| AtomicUsize::new(0));
155 counter.fetch_add(1, Ordering::Relaxed);
156 }
157
158 fn store_recent_error(&self, error: MemScopeError) {
159 if let Ok(mut recent) = self.recent_errors.lock() {
160 recent.push(error);
161
162 if recent.len() > self.max_recent_errors {
164 let excess = recent.len() - self.max_recent_errors;
165 recent.drain(0..excess);
166 }
167 }
168 }
169
170 fn determine_response(&self, error: &MemScopeError) -> ErrorResponse {
171 match error.severity() {
172 ErrorSeverity::Warning => ErrorResponse::Continue,
173 ErrorSeverity::Error => {
174 if self.is_frequent_error(&error.kind()) {
175 ErrorResponse::Throttle
176 } else {
177 ErrorResponse::Retry
178 }
179 }
180 ErrorSeverity::Critical => ErrorResponse::Fallback,
181 ErrorSeverity::Fatal => ErrorResponse::Abort,
182 }
183 }
184
185 fn is_frequent_error(&self, kind: &ErrorKind) -> bool {
186 self.error_counts
187 .get(kind)
188 .map(|count| count.load(Ordering::Relaxed) > 10)
189 .unwrap_or(false)
190 }
191
192 fn log_response(&self, error: &MemScopeError, response: &ErrorResponse) {
193 if self.reporter.log_to_stderr {
194 error!(
195 "ErrorHandler: {} -> Response: {:?}",
196 error.description(),
197 response
198 );
199 }
200 }
201}
202
203impl ErrorReporter {
204 pub fn new() -> Self {
206 Self {
207 log_to_stderr: true,
208 store_errors: true,
209 min_severity: ErrorSeverity::Warning,
210 custom_handlers: HashMap::new(),
211 }
212 }
213
214 pub fn with_logging(mut self, enabled: bool) -> Self {
216 self.log_to_stderr = enabled;
217 self
218 }
219
220 pub fn with_storage(mut self, enabled: bool) -> Self {
222 self.store_errors = enabled;
223 self
224 }
225
226 pub fn with_min_severity(mut self, severity: ErrorSeverity) -> Self {
228 self.min_severity = severity;
229 self
230 }
231
232 pub fn with_custom_handler<F>(mut self, severity: ErrorSeverity, handler: F) -> Self
234 where
235 F: Fn(&MemScopeError) + Send + Sync + 'static,
236 {
237 self.custom_handlers.insert(severity, Box::new(handler));
238 self
239 }
240
241 pub fn report_error(&self, error: &MemScopeError) -> bool {
243 if error.severity() < self.min_severity {
244 return false;
245 }
246
247 if let Some(handler) = self.custom_handlers.get(&error.severity()) {
249 handler(error);
250 }
251
252 if self.log_to_stderr {
254 error!("MemScope Error: {}", error);
255 }
256
257 true
258 }
259}
260
261#[derive(Debug, Clone, PartialEq)]
263pub enum ErrorResponse {
264 Continue,
266 Retry,
268 Throttle,
270 Fallback,
272 Abort,
274}
275
276impl ErrorResponse {
277 pub fn should_log(&self) -> bool {
279 !matches!(self, ErrorResponse::Continue)
280 }
281
282 pub fn should_retry(&self) -> bool {
284 matches!(self, ErrorResponse::Retry)
285 }
286
287 pub fn should_abort(&self) -> bool {
289 matches!(self, ErrorResponse::Abort)
290 }
291}
292
293#[derive(Debug, Clone)]
295pub struct ErrorFrequencyAnalysis {
296 pub total_errors: usize,
298 pub most_common_error: Option<(ErrorKind, usize)>,
300 pub errors_per_second: f64,
302 pub error_distribution: HashMap<ErrorKind, usize>,
304}
305
306impl ErrorFrequencyAnalysis {
307 pub fn is_error_rate_high(&self) -> bool {
309 self.errors_per_second > 1.0 || self.total_errors > 100
310 }
311
312 pub fn get_primary_concern(&self) -> Option<ErrorKind> {
314 self.most_common_error.as_ref().map(|(kind, _)| *kind)
315 }
316
317 pub fn summary(&self) -> String {
319 format!(
320 "Error Analysis: {} total errors, {:.2} errors/sec, primary concern: {:?}",
321 self.total_errors,
322 self.errors_per_second,
323 self.get_primary_concern()
324 )
325 }
326}
327
328impl Default for ErrorHandler {
329 fn default() -> Self {
330 Self::new()
331 }
332}
333
334impl Default for ErrorReporter {
335 fn default() -> Self {
336 Self::new()
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_error_handler_basic() {
346 let mut handler = ErrorHandler::new();
347 let error = MemScopeError::new(ErrorKind::MemoryError, "test error");
348
349 let response = handler.handle_error(error);
350 assert_eq!(response, ErrorResponse::Retry);
351
352 let counts = handler.get_error_counts();
353 assert_eq!(counts.get(&ErrorKind::MemoryError), Some(&1));
354 }
355
356 #[test]
357 fn test_error_frequency_analysis() {
358 let mut handler = ErrorHandler::new();
359
360 for _ in 0..5 {
362 let error = MemScopeError::new(ErrorKind::CacheError, "cache miss");
363 handler.handle_error(error);
364 }
365
366 for _ in 0..3 {
367 let error = MemScopeError::new(ErrorKind::MemoryError, "allocation failed");
368 handler.handle_error(error);
369 }
370
371 let analysis = handler.get_error_frequency();
372 assert_eq!(analysis.total_errors, 8);
373 assert_eq!(analysis.get_primary_concern(), Some(ErrorKind::CacheError));
374 }
375
376 #[test]
377 fn test_error_reporter_configuration() {
378 let reporter = ErrorReporter::new()
379 .with_logging(false)
380 .with_storage(true)
381 .with_min_severity(ErrorSeverity::Error);
382
383 let validation_err = MemScopeError::with_context(
386 ErrorKind::ValidationError,
387 ErrorSeverity::Warning,
388 "test_warning",
389 "test",
390 );
391 assert!(reporter.report_error(&validation_err));
393
394 let error = MemScopeError::with_context(
396 ErrorKind::MemoryError,
397 ErrorSeverity::Error,
398 "test_error",
399 "test",
400 );
401 assert!(reporter.report_error(&error));
402 }
403
404 #[test]
405 fn test_error_response_strategies() {
406 let handler = ErrorHandler::new();
407
408 let validation_err = MemScopeError::with_context(
410 ErrorKind::ValidationError,
411 ErrorSeverity::Warning,
412 "test",
413 "test",
414 );
415 let response = handler.determine_response(&validation_err);
416 assert_eq!(response, ErrorResponse::Retry);
418 assert!(!response.should_abort());
419
420 let fatal = MemScopeError::with_context(
421 ErrorKind::InternalError,
422 ErrorSeverity::Fatal,
423 "test",
424 "test",
425 );
426 let response = handler.determine_response(&fatal);
427 assert_eq!(response, ErrorResponse::Abort);
429 assert!(response.should_abort());
430 }
431}