# Error Handling Guide ## Overview This guide describes the error handling system implemented in the v2_adminpanel application. The system provides: - Centralized error handling with custom exception hierarchy - Input validation framework - Structured logging - Monitoring and alerting - Consistent error responses ## Architecture ### 1. Custom Exception Hierarchy ``` BaseApplicationException ├── ValidationException │ ├── InputValidationError │ ├── BusinessRuleViolation │ └── DataIntegrityError ├── AuthenticationException │ ├── InvalidCredentialsError │ ├── SessionExpiredError │ └── InsufficientPermissionsError ├── DatabaseException │ ├── ConnectionError │ ├── QueryError │ └── TransactionError ├── ExternalServiceException │ ├── APIError │ └── TimeoutError └── ResourceException ├── ResourceNotFoundError ├── ResourceConflictError └── ResourceLimitExceeded ``` ### 2. Core Components - **core/exceptions.py**: Custom exception classes - **core/error_handlers.py**: Global error handlers and decorators - **core/validators.py**: Input validation framework - **core/logging_config.py**: Structured logging setup - **core/monitoring.py**: Error metrics and alerting - **middleware/error_middleware.py**: Request-level error handling ## Usage Examples ### 1. Raising Custom Exceptions ```python from core.exceptions import ( InputValidationError, ResourceNotFoundError, BusinessRuleViolation ) # Validation error if not email_is_valid: raise InputValidationError( field='email', message='Invalid email format', value=email_value, expected_type='email' ) # Resource not found user = db.get_user(user_id) if not user: raise ResourceNotFoundError( resource_type='User', resource_id=user_id ) # Business rule violation if active_licenses >= license_limit: raise BusinessRuleViolation( rule='license_limit', message='License limit exceeded', context={ 'current': active_licenses, 'limit': license_limit } ) ``` ### 2. Using Error Decorators ```python from core.error_handlers import handle_errors, validate_request from core.validators import validate @handle_errors( catch=(psycopg2.Error,), message='Database operation failed', user_message='Datenbankfehler aufgetreten', redirect_to='admin.dashboard' ) def update_customer(customer_id): # Database operations pass @validate_request( required_fields={ 'email': str, 'age': int, 'active': bool } ) def create_user(): # Request data is validated pass @validate({ 'email': { 'type': 'email', 'required': True }, 'password': { 'type': 'password', 'required': True }, 'age': { 'type': 'integer', 'required': True, 'min_value': 18, 'max_value': 120 } }) def register_user(): # Access validated data data = request.validated_data # Use data safely ``` ### 3. Input Validation ```python from core.validators import Validators # Email validation email = Validators.email(user_input, field_name='email') # Phone validation phone = Validators.phone(user_input, field_name='phone') # License key validation license_key = Validators.license_key(user_input) # Integer with constraints age = Validators.integer( user_input, field_name='age', min_value=0, max_value=150 ) # String with constraints username = Validators.string( user_input, field_name='username', min_length=3, max_length=50, safe_only=True ) # Password validation password = Validators.password(user_input) # Custom enum validation status = Validators.enum( user_input, field_name='status', allowed_values=['active', 'inactive', 'pending'] ) ``` ### 4. Error Context Manager ```python from core.error_handlers import ErrorContext with ErrorContext( operation='create_license', resource_type='License', resource_id=license_key ): # Operations that might fail db.insert_license(license_data) # Errors are automatically logged with context ``` ### 5. Logging ```python from core.logging_config import get_logger, log_error, log_security_event logger = get_logger(__name__) # Standard logging logger.info('User created', extra={ 'user_id': user.id, 'email': user.email }) # Error logging try: risky_operation() except Exception as e: log_error( logger, 'Risky operation failed', error=e, user_id=user.id, operation='risky_operation' ) # Security event logging log_security_event( 'INVALID_LOGIN_ATTEMPT', 'Multiple failed login attempts', username=username, ip_address=request.remote_addr, attempt_count=5 ) ``` ## Error Response Format ### JSON Responses (API) ```json { "error": { "code": "VALIDATION_ERROR", "message": "Invalid input provided", "timestamp": "2024-01-15T10:30:00Z", "request_id": "550e8400-e29b-41d4-a716-446655440000", "details": { "field": "email", "value": "invalid-email", "expected_type": "email" } } } ``` ### HTML Responses - User-friendly error messages - Error code and request ID for support - Helpful suggestions for resolution - Navigation options (back, dashboard, retry) ## Monitoring and Alerts ### Metrics Exposed - `app_errors_total`: Total error count by code, status, endpoint - `app_error_rate`: Errors per minute by error code - `app_validation_errors_total`: Validation errors by field - `app_auth_failures_total`: Authentication failures - `app_database_errors_total`: Database errors - `app_request_duration_seconds`: Request duration histogram ### Alert Thresholds - Error rate > 10/min: Critical alert - Auth failure rate > 5/min: Security alert - DB error rate > 3/min: Infrastructure alert - Response time 95th percentile > 2s: Performance alert ### Accessing Metrics - Prometheus metrics: `/metrics` - Active alerts: `/api/alerts` ## Best Practices ### 1. Always Use Specific Exceptions ```python # Bad raise Exception("User not found") # Good raise ResourceNotFoundError('User', user_id) ``` ### 2. Provide Context ```python # Bad raise ValidationException("Invalid data") # Good raise InputValidationError( field='email', message='Email domain not allowed', value=email, expected_type='corporate_email' ) ``` ### 3. Handle Database Errors ```python # Bad result = db.execute(query) # Good try: result = db.execute(query) except psycopg2.IntegrityError as e: if e.pgcode == '23505': raise DataIntegrityError( entity='User', constraint='unique_email', message='Email already exists' ) raise ``` ### 4. Validate Early ```python # Bad def process_order(data): # Process without validation total = data['quantity'] * data['price'] # Good @validate({ 'quantity': {'type': 'integer', 'min_value': 1}, 'price': {'type': 'float', 'min_value': 0} }) def process_order(): data = request.validated_data total = data['quantity'] * data['price'] ``` ### 5. Log Security Events ```python # Failed login attempts log_security_event( 'LOGIN_FAILURE', f'Failed login for user {username}', username=username, ip_address=request.remote_addr ) # Suspicious activity log_security_event( 'SUSPICIOUS_ACTIVITY', 'Rapid API requests detected', ip_address=request.remote_addr, request_count=count, time_window=60 ) ``` ## Migration Guide ### Converting Existing Error Handling 1. **Replace generic exceptions**: ```python # Old except Exception as e: flash(f"Error: {str(e)}", "error") return redirect(url_for('admin.dashboard')) # New except DatabaseException as e: # Already handled by global handler raise ``` 2. **Update validation**: ```python # Old email = request.form.get('email') if not email or '@' not in email: flash("Invalid email", "error") return redirect(request.url) # New from core.validators import Validators try: email = Validators.email(request.form.get('email')) except InputValidationError as e: # Handled automatically raise ``` 3. **Use decorators**: ```python # Old @app.route('/api/user', methods=['POST']) def create_user(): try: # validation code # database operations except Exception as e: return jsonify({'error': str(e)}), 500 # New @app.route('/api/user', methods=['POST']) @validate({ 'email': {'type': 'email', 'required': True}, 'name': {'type': 'string', 'required': True, 'min_length': 2} }) def create_user(): data = request.validated_data # Use validated data directly ``` ## Testing Run the test suite: ```bash pytest v2_adminpanel/tests/test_error_handling.py -v ``` Test coverage includes: - Exception creation and properties - Error handler responses (JSON/HTML) - Validation functions - Decorators - Monitoring and metrics - Alert generation ## Troubleshooting ### Common Issues 1. **Import errors**: Ensure you import from `core` package 2. **Validation not working**: Check decorator order (validate must be closest to function) 3. **Logs not appearing**: Verify LOG_LEVEL environment variable 4. **Metrics missing**: Ensure prometheus_client is installed ### Debug Mode In development, set: ```python app.config['DEBUG'] = True ``` This will: - Include detailed error information - Show stack traces - Log to console with readable format