Files
v2-Docker/v2_adminpanel/ERROR_HANDLING_GUIDE.md
Claude Project Manager 0d7d888502 Initial commit
2025-07-05 17:51:16 +02:00

9.5 KiB

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

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

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

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

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

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)

{
    "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

# Bad
raise Exception("User not found")

# Good
raise ResourceNotFoundError('User', user_id)

2. Provide Context

# 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

# 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

# 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

# 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:
# 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
  1. Update validation:
# 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
  1. Use decorators:
# 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:

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:

app.config['DEBUG'] = True

This will:

  • Include detailed error information
  • Show stack traces
  • Log to console with readable format