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