1use super::{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.clone(), 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.clone(), *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 let duration = newest.duration_since(oldest).as_secs_f64();
123 if duration > 0.0 {
124 recent.len() as f64 / duration
125 } else {
126 0.0
127 }
128 } else {
129 0.0
130 }
131 }
132 } else {
133 0.0
134 };
135
136 ErrorFrequencyAnalysis {
137 total_errors,
138 most_common_error: most_common,
139 errors_per_second: error_rate,
140 error_distribution: counts,
141 }
142 }
143
144 fn update_statistics(&mut self, error: &MemScopeError) {
145 let counter = self
146 .error_counts
147 .entry(error.kind.clone())
148 .or_insert_with(|| AtomicUsize::new(0));
149 counter.fetch_add(1, Ordering::Relaxed);
150 }
151
152 fn store_recent_error(&self, error: MemScopeError) {
153 if let Ok(mut recent) = self.recent_errors.lock() {
154 recent.push(error);
155
156 if recent.len() > self.max_recent_errors {
158 let excess = recent.len() - self.max_recent_errors;
159 recent.drain(0..excess);
160 }
161 }
162 }
163
164 fn determine_response(&self, error: &MemScopeError) -> ErrorResponse {
165 match error.severity {
166 ErrorSeverity::Warning => ErrorResponse::Continue,
167 ErrorSeverity::Error => {
168 if self.is_frequent_error(&error.kind) {
169 ErrorResponse::Throttle
170 } else {
171 ErrorResponse::Retry
172 }
173 }
174 ErrorSeverity::Critical => ErrorResponse::Fallback,
175 ErrorSeverity::Fatal => ErrorResponse::Abort,
176 }
177 }
178
179 fn is_frequent_error(&self, kind: &ErrorKind) -> bool {
180 self.error_counts
181 .get(kind)
182 .map(|count| count.load(Ordering::Relaxed) > 10)
183 .unwrap_or(false)
184 }
185
186 fn log_response(&self, error: &MemScopeError, response: &ErrorResponse) {
187 if self.reporter.log_to_stderr {
188 eprintln!(
189 "ErrorHandler: {} -> Response: {:?}",
190 error.description(),
191 response
192 );
193 }
194 }
195}
196
197impl ErrorReporter {
198 pub fn new() -> Self {
200 Self {
201 log_to_stderr: true,
202 store_errors: true,
203 min_severity: ErrorSeverity::Warning,
204 custom_handlers: HashMap::new(),
205 }
206 }
207
208 pub fn with_logging(mut self, enabled: bool) -> Self {
210 self.log_to_stderr = enabled;
211 self
212 }
213
214 pub fn with_storage(mut self, enabled: bool) -> Self {
216 self.store_errors = enabled;
217 self
218 }
219
220 pub fn with_min_severity(mut self, severity: ErrorSeverity) -> Self {
222 self.min_severity = severity;
223 self
224 }
225
226 pub fn with_custom_handler<F>(mut self, severity: ErrorSeverity, handler: F) -> Self
228 where
229 F: Fn(&MemScopeError) + Send + Sync + 'static,
230 {
231 self.custom_handlers.insert(severity, Box::new(handler));
232 self
233 }
234
235 pub fn report_error(&self, error: &MemScopeError) -> bool {
237 if error.severity < self.min_severity {
238 return false;
239 }
240
241 if let Some(handler) = self.custom_handlers.get(&error.severity) {
243 handler(error);
244 }
245
246 if self.log_to_stderr {
248 eprintln!("MemScope Error: {}", error);
249 }
250
251 true
252 }
253}
254
255#[derive(Debug, Clone, PartialEq)]
257pub enum ErrorResponse {
258 Continue,
260 Retry,
262 Throttle,
264 Fallback,
266 Abort,
268}
269
270impl ErrorResponse {
271 pub fn should_log(&self) -> bool {
273 !matches!(self, ErrorResponse::Continue)
274 }
275
276 pub fn should_retry(&self) -> bool {
278 matches!(self, ErrorResponse::Retry)
279 }
280
281 pub fn should_abort(&self) -> bool {
283 matches!(self, ErrorResponse::Abort)
284 }
285}
286
287#[derive(Debug, Clone)]
289pub struct ErrorFrequencyAnalysis {
290 pub total_errors: usize,
292 pub most_common_error: Option<(ErrorKind, usize)>,
294 pub errors_per_second: f64,
296 pub error_distribution: HashMap<ErrorKind, usize>,
298}
299
300impl ErrorFrequencyAnalysis {
301 pub fn is_error_rate_high(&self) -> bool {
303 self.errors_per_second > 1.0 || self.total_errors > 100
304 }
305
306 pub fn get_primary_concern(&self) -> Option<ErrorKind> {
308 self.most_common_error
309 .as_ref()
310 .map(|(kind, _)| kind.clone())
311 }
312
313 pub fn summary(&self) -> String {
315 format!(
316 "Error Analysis: {} total errors, {:.2} errors/sec, primary concern: {:?}",
317 self.total_errors,
318 self.errors_per_second,
319 self.get_primary_concern()
320 )
321 }
322}
323
324impl Default for ErrorHandler {
325 fn default() -> Self {
326 Self::new()
327 }
328}
329
330impl Default for ErrorReporter {
331 fn default() -> Self {
332 Self::new()
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn test_error_handler_basic() {
342 let mut handler = ErrorHandler::new();
343 let error = MemScopeError::new(ErrorKind::MemoryError, "test error");
344
345 let response = handler.handle_error(error);
346 assert_eq!(response, ErrorResponse::Retry);
347
348 let counts = handler.get_error_counts();
349 assert_eq!(counts.get(&ErrorKind::MemoryError), Some(&1));
350 }
351
352 #[test]
353 fn test_error_frequency_analysis() {
354 let mut handler = ErrorHandler::new();
355
356 for _ in 0..5 {
358 let error = MemScopeError::new(ErrorKind::CacheError, "cache miss");
359 handler.handle_error(error);
360 }
361
362 for _ in 0..3 {
363 let error = MemScopeError::new(ErrorKind::MemoryError, "allocation failed");
364 handler.handle_error(error);
365 }
366
367 let analysis = handler.get_error_frequency();
368 assert_eq!(analysis.total_errors, 8);
369 assert_eq!(analysis.get_primary_concern(), Some(ErrorKind::CacheError));
370 }
371
372 #[test]
373 fn test_error_reporter_configuration() {
374 let reporter = ErrorReporter::new()
375 .with_logging(false)
376 .with_storage(true)
377 .with_min_severity(ErrorSeverity::Error);
378
379 let warning = MemScopeError::with_context(
381 ErrorKind::ValidationError,
382 ErrorSeverity::Warning,
383 "test_warning",
384 "test",
385 );
386 assert!(!reporter.report_error(&warning));
387
388 let error = MemScopeError::with_context(
390 ErrorKind::ValidationError,
391 ErrorSeverity::Error,
392 "test_error",
393 "test",
394 );
395 assert!(reporter.report_error(&error));
396 }
397
398 #[test]
399 fn test_error_response_strategies() {
400 let handler = ErrorHandler::new();
401
402 let warning = MemScopeError::with_context(
403 ErrorKind::ValidationError,
404 ErrorSeverity::Warning,
405 "test",
406 "test",
407 );
408 let response = handler.determine_response(&warning);
409 assert_eq!(response, ErrorResponse::Continue);
410 assert!(!response.should_abort());
411
412 let fatal = MemScopeError::with_context(
413 ErrorKind::InternalError,
414 ErrorSeverity::Fatal,
415 "test",
416 "test",
417 );
418 let response = handler.determine_response(&fatal);
419 assert_eq!(response, ErrorResponse::Abort);
420 assert!(response.should_abort());
421 }
422}