Skip to main content

leptos_forms_rs/error/
reporter.rs

1//! Error reporter module - Error reporting to external services
2//!
3//! This module provides the ErrorReporter trait and implementations,
4//! error reporting strategies, and external service integration points.
5
6use super::{ErrorContext, FormError};
7
8/// Error reporting service trait
9pub trait ErrorReporter {
10    /// Report an error to external service
11    fn report_error(&self, error: &FormError, context: &ErrorContext);
12}
13
14/// Console error reporter (for development)
15pub struct ConsoleErrorReporter;
16
17impl ErrorReporter for ConsoleErrorReporter {
18    fn report_error(&self, error: &FormError, context: &ErrorContext) {
19        log::error!("Error reported: {} (context: {:?})", error, context);
20    }
21}
22
23/// File error reporter that writes errors to a file
24pub struct FileErrorReporter {
25    file_path: String,
26}
27
28impl FileErrorReporter {
29    /// Create a new file error reporter
30    pub fn new(file_path: impl Into<String>) -> Self {
31        Self {
32            file_path: file_path.into(),
33        }
34    }
35
36    /// Get the file path
37    pub fn file_path(&self) -> &str {
38        &self.file_path
39    }
40}
41
42impl ErrorReporter for FileErrorReporter {
43    fn report_error(&self, error: &FormError, context: &ErrorContext) {
44        // In a real implementation, this would write to a file
45        // For now, we'll just log it
46        log::error!(
47            "Error reported to file {}: {} (context: {:?})",
48            self.file_path,
49            error,
50            context
51        );
52    }
53}
54
55/// HTTP error reporter that sends errors to an HTTP endpoint
56pub struct HttpErrorReporter {
57    endpoint: String,
58    api_key: Option<String>,
59}
60
61impl HttpErrorReporter {
62    /// Create a new HTTP error reporter
63    pub fn new(endpoint: impl Into<String>) -> Self {
64        Self {
65            endpoint: endpoint.into(),
66            api_key: None,
67        }
68    }
69
70    /// Create a new HTTP error reporter with API key
71    pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
72        self.api_key = Some(api_key.into());
73        self
74    }
75
76    /// Get the endpoint
77    pub fn endpoint(&self) -> &str {
78        &self.endpoint
79    }
80
81    /// Check if API key is set
82    pub fn has_api_key(&self) -> bool {
83        self.api_key.is_some()
84    }
85}
86
87impl ErrorReporter for HttpErrorReporter {
88    fn report_error(&self, error: &FormError, context: &ErrorContext) {
89        // In a real implementation, this would make an HTTP request
90        // For now, we'll just log it
91        log::error!(
92            "Error reported to HTTP endpoint {}: {} (context: {:?})",
93            self.endpoint,
94            error,
95            context
96        );
97    }
98}
99
100/// Composite error reporter that reports to multiple services
101pub struct CompositeErrorReporter {
102    reporters: Vec<Box<dyn ErrorReporter + Send + Sync>>,
103}
104
105impl CompositeErrorReporter {
106    /// Create a new composite error reporter
107    pub fn new() -> Self {
108        Self {
109            reporters: Vec::new(),
110        }
111    }
112
113    /// Add a reporter to the composite
114    pub fn add_reporter(mut self, reporter: Box<dyn ErrorReporter + Send + Sync>) -> Self {
115        self.reporters.push(reporter);
116        self
117    }
118
119    /// Get the number of reporters
120    pub fn reporter_count(&self) -> usize {
121        self.reporters.len()
122    }
123}
124
125impl Default for CompositeErrorReporter {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131impl ErrorReporter for CompositeErrorReporter {
132    fn report_error(&self, error: &FormError, context: &ErrorContext) {
133        for reporter in &self.reporters {
134            reporter.report_error(error, context);
135        }
136    }
137}
138
139/// Utility functions for error handling
140pub mod utils {
141    use super::*;
142    use crate::error::field_error;
143
144    /// Create a field error from a validation error
145    pub fn field_error_from_validation(field: &str, message: &str) -> FormError {
146        FormError::field_error(field, message)
147    }
148
149    /// Create a validation error from multiple field errors
150    pub fn validation_error_from_fields(
151        message: &str,
152        field_errors: Vec<field_error::FieldError>,
153    ) -> FormError {
154        FormError::validation_error(message, field_errors)
155    }
156
157    /// Extract field errors from a form error
158    pub fn extract_field_errors(error: &FormError) -> Vec<field_error::FieldError> {
159        match error {
160            FormError::ValidationError { field_errors, .. } => field_errors.clone(),
161            FormError::FieldError {
162                field,
163                message,
164                code,
165            } => {
166                vec![field_error::FieldError {
167                    field: field.clone(),
168                    message: message.clone(),
169                    code: code.clone(),
170                }]
171            }
172            _ => Vec::new(),
173        }
174    }
175
176    /// Check if an error is recoverable
177    pub fn is_recoverable_error(error: &FormError) -> bool {
178        matches!(
179            error,
180            FormError::FieldError { .. }
181                | FormError::ValidationError { .. }
182                | FormError::SerializationError { .. }
183        )
184    }
185
186    /// Check if an error is critical
187    pub fn is_critical_error(error: &FormError) -> bool {
188        matches!(
189            error,
190            FormError::StateError { .. } | FormError::ConfigurationError { .. }
191        )
192    }
193
194    /// Get error severity level
195    pub fn get_error_severity(error: &FormError) -> ErrorSeverity {
196        match error {
197            FormError::FieldError { .. } => ErrorSeverity::Low,
198            FormError::ValidationError { .. } => ErrorSeverity::Medium,
199            FormError::SerializationError { .. } => ErrorSeverity::Medium,
200            FormError::SubmissionError { .. } => ErrorSeverity::High,
201            FormError::StateError { .. } => ErrorSeverity::Critical,
202            FormError::PersistenceError { .. } => ErrorSeverity::High,
203            FormError::ConfigurationError { .. } => ErrorSeverity::Critical,
204            FormError::Unknown { .. } => ErrorSeverity::High,
205        }
206    }
207
208    /// Format error for logging
209    pub fn format_error_for_logging(error: &FormError, context: &ErrorContext) -> String {
210        format!("Error: {} | Context: {}", error, context)
211    }
212
213    /// Format error for reporting
214    pub fn format_error_for_reporting(error: &FormError, context: &ErrorContext) -> String {
215        let severity = get_error_severity(error);
216        format!("[{}] {} | Context: {}", severity, error, context)
217    }
218}
219
220/// Error severity levels
221#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
222pub enum ErrorSeverity {
223    Low,
224    Medium,
225    High,
226    Critical,
227}
228
229impl std::fmt::Display for ErrorSeverity {
230    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231        match self {
232            ErrorSeverity::Low => write!(f, "LOW"),
233            ErrorSeverity::Medium => write!(f, "MEDIUM"),
234            ErrorSeverity::High => write!(f, "HIGH"),
235            ErrorSeverity::Critical => write!(f, "CRITICAL"),
236        }
237    }
238}