CMS Framework - v1.0.0

Error Handling Strategy

Table of Contents

  1. Overview
  2. Architecture
  3. Exception Hierarchy
  4. Services
  5. Configuration
  6. Artisan Commands
  7. Middleware
  8. Usage Examples
  9. Testing
  10. Best Practices
  11. Troubleshooting

Overview

The CMS Framework implements a comprehensive error handling and logging strategy designed to provide robust error management, detailed logging, audit trails, and recovery mechanisms for Laravel applications. The system is built with scalability, security, and developer experience in mind.

Key Features

  • Structured Exception Hierarchy: Domain-specific exceptions with rich context
  • Multi-Channel Logging: Separate logs for errors, audit trails, and security events
  • Error Tracking Integration: Support for Sentry, Bugsnag, Rollbar, and custom providers
  • Automatic Recovery: Built-in error recovery mechanisms
  • Performance Monitoring: Track error handling performance
  • Security-First: Data sanitization and secure logging practices
  • Developer Tools: Comprehensive Artisan commands for log management and analysis

Architecture

The error handling system is built around several core components:

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Exceptions    │    │    Services      │    │   Middleware    │
│                 │    │                  │    │                 │
│ • CMSException  │───▶│ • ErrorTracking  │◀───│ • ErrorHandling │
│ • AuthException │    │ • StructuredLog  │    │                 │
│ • ContentExc... │    │ • AuditLogger    │    └─────────────────┘
│ • MediaExc...   │    │                  │              │
│ • PluginExc...  │    └──────────────────┘              │
│ • UserExc...    │             │                        │
└─────────────────┘             ▼                        ▼
         │              ┌──────────────────┐    ┌─────────────────┐
         │              │  Configuration   │    │    Commands     │
         │              │                  │    │                 │
         └─────────────▶│ • Tracking       │    │ • LogView       │
                        │ • Logging        │    │ • LogAnalysis   │
                        │ • Audit          │    │ • LogCleanup    │
                        │ • Recovery       │    │ • ErrorTesting  │
                        │ • Notifications  │    │                 │
                        └──────────────────┘    └─────────────────┘

Exception Hierarchy

Base Exception: CMSException

All CMS-specific exceptions extend from the base CMSException class, which provides:

  • Rich context support
  • Custom error response rendering
  • Integration with tracking services
  • Structured logging support
use ArtisanPackUI\CMSFramework\Exceptions\CMSException;

throw new CMSException(
    message: 'Something went wrong',
    code: 500,
    previous: null,
    context: ['user_id' => auth()->id(), 'action' => 'update_content']
);

Specialized Exceptions

AuthorizationException

For permission and access control errors:

use ArtisanPackUI\CMSFramework\Exceptions\AuthorizationException;

throw new AuthorizationException(
    message: 'Access denied to resource',
    permission: 'content.edit',
    code: 403,
    context: ['resource_id' => $contentId, 'user_roles' => $userRoles]
);

ContentException

For content management errors:

use ArtisanPackUI\CMSFramework\Exceptions\ContentException;

throw new ContentException(
    message: 'Content validation failed',
    contentId: $content->id,
    errorType: 'validation_failed',
    code: 422,
    context: ['validation_errors' => $validator->errors()]
);

MediaException

For file and media handling errors:

use ArtisanPackUI\CMSFramework\Exceptions\MediaException;

throw new MediaException(
    message: 'File upload failed',
    fileName: $file->getClientOriginalName(),
    errorType: 'upload_failed',
    code: 422,
    context: ['file_size' => $file->getSize(), 'max_size' => $maxSize]
);

PluginException

For plugin system errors:

use ArtisanPackUI\CMSFramework\Exceptions\PluginException;

throw new PluginException(
    message: 'Plugin activation failed',
    pluginName: $pluginName,
    errorType: 'activation_failed',
    code: 500,
    context: ['dependencies' => $missingDeps]
);

UserException

For user management errors:

use ArtisanPackUI\CMSFramework\Exceptions\UserException;

throw new UserException(
    message: 'User registration failed',
    action: 'registration',
    code: 400,
    context: ['validation_errors' => $errors]
);

Services

ErrorTrackingService

Handles error tracking with external services and internal logging:

use ArtisanPackUI\CMSFramework\Services\ErrorTrackingService;

$errorTracker = app(ErrorTrackingService::class);

// Track an error
$errorTracker->trackError($exception, $context);

// Get tracked error details
$errorId = $errorTracker->getLastTrackedErrorId();
$errorDetails = $errorTracker->getTrackedError($errorId);

// Attempt recovery
$errorTracker->attemptRecovery($exception, $context);

StructuredLoggerService

Provides structured logging with consistent formatting:

use ArtisanPackUI\CMSFramework\Services\StructuredLoggerService;

$logger = app(StructuredLoggerService::class);

// Log an error with structured context
$logger->logError($exception, $context, 'error');

// Log custom structured data
$logger->logStructured('info', 'User action performed', [
    'user_id' => auth()->id(),
    'action' => 'content_published',
    'content_id' => $content->id,
]);

AuditLoggerService

Handles audit logging for compliance and security:

use ArtisanPackUI\CMSFramework\Services\AuditLoggerService;

$auditLogger = app(AuditLoggerService::class);

// Log error handling event
$auditLogger->logErrorHandling([
    'event' => 'error_occurred',
    'user_id' => auth()->id(),
    'error_type' => 'authorization_exception',
    'severity' => 'warning',
    'handled' => true,
    'context' => $context,
]);

Configuration

The error handling system is configured via config/cms-error-handling.php. Key configuration sections:

Error Tracking

'tracking' => [
    'enabled' => env('CMS_ERROR_TRACKING_ENABLED', true),
    'provider' => env('CMS_ERROR_TRACKING_PROVIDER', 'sentry'),
    'providers' => [
        'sentry' => [
            'dsn' => env('SENTRY_LARAVEL_DSN'),
            'sample_rate' => 1.0,
        ],
    ],
],

Logging Channels

'logging' => [
    'channels' => [
        'cms' => [
            'driver' => 'daily',
            'path' => storage_path('logs/cms/cms.log'),
            'level' => 'debug',
            'days' => 14,
        ],
        'errors' => [
            'driver' => 'daily',
            'path' => storage_path('logs/cms/errors.log'),
            'level' => 'error',
            'days' => 30,
        ],
        'audit' => [
            'driver' => 'daily',
            'path' => storage_path('logs/cms/audit.log'),
            'level' => 'info',
            'days' => 90,
        ],
    ],
],

Security Settings

'security' => [
    'sanitize_data' => true,
    'sensitive_fields' => [
        'password', 'token', 'api_key', 'secret',
    ],
    'separate_security_logs' => true,
],

Artisan Commands

View Error Logs

# View recent error logs
php artisan cms:error-logs:view

# View specific number of lines
php artisan cms:error-logs:view --lines=50

# Filter by log level
php artisan cms:error-logs:view --level=error

# Follow logs in real-time
php artisan cms:error-logs:view --follow

# Search for specific content
php artisan cms:error-logs:view --search="user_id:123"

Analyze Error Logs

# Analyze errors from last hour
php artisan cms:error-logs:analyze --period=1h

# Generate detailed report
php artisan cms:error-logs:analyze --detailed

# Export analysis to file
php artisan cms:error-logs:analyze --export=json --output=/path/to/report.json

# Analyze specific error types
php artisan cms:error-logs:analyze --type=cms_exception

Clean Up Logs

# Clean up old logs (default: 30 days)
php artisan cms:error-logs:cleanup

# Specify retention period
php artisan cms:error-logs:cleanup --days=7

# Compress instead of delete
php artisan cms:error-logs:cleanup --compress

# Dry run to see what would be cleaned
php artisan cms:error-logs:cleanup --dry-run

Test Error Handling

# Test all error types
php artisan cms:error-logs:test

# Test specific error type
php artisan cms:error-logs:test --type=auth

# Generate multiple test errors
php artisan cms:error-logs:test --count=5

# Test with recovery mechanisms
php artisan cms:error-logs:test --test-recovery

# Verify logs after testing
php artisan cms:error-logs:test --verify-logs

Middleware

The ErrorHandlingMiddleware automatically catches and processes exceptions:

Registration

Add to your middleware stack in bootstrap/app.php:

use ArtisanPackUI\CMSFramework\Http\Middleware\ErrorHandlingMiddleware;

$app->middleware([
    ErrorHandlingMiddleware::class,
]);

Functionality

The middleware automatically:

  • Captures exceptions
  • Logs them through the structured logger
  • Tracks them via the error tracking service
  • Creates audit log entries
  • Attempts recovery when appropriate
  • Returns appropriate error responses

Usage Examples

Basic Error Handling in Controllers

<?php

namespace App\Http\Controllers;

use ArtisanPackUI\CMSFramework\Exceptions\ContentException;
use ArtisanPackUI\CMSFramework\Services\StructuredLoggerService;

class ContentController extends Controller
{
    public function update(Request $request, Content $content)
    {
        try {
            // Validate and update content
            $validated = $request->validate([
                'title' => 'required|string|max:255',
                'body' => 'required|string',
            ]);
            
            $content->update($validated);
            
            return response()->json(['success' => true]);
            
        } catch (ValidationException $e) {
            // Throw domain-specific exception with context
            throw new ContentException(
                message: 'Content validation failed',
                contentId: $content->id,
                errorType: 'validation_failed',
                code: 422,
                context: [
                    'user_id' => auth()->id(),
                    'validation_errors' => $e->errors(),
                    'request_data' => $request->except(['password', 'token']),
                ]
            );
        }
    }
}

Custom Error Handling in Services

<?php

namespace App\Services;

use ArtisanPackUI\CMSFramework\Exceptions\MediaException;
use ArtisanPackUI\CMSFramework\Services\AuditLoggerService;

class MediaService
{
    public function __construct(
        private AuditLoggerService $auditLogger
    ) {}

    public function uploadFile(UploadedFile $file): Media
    {
        try {
            // Validate file
            if ($file->getSize() > config('media.max_file_size')) {
                throw new MediaException(
                    message: 'File size exceeds limit',
                    fileName: $file->getClientOriginalName(),
                    errorType: 'file_too_large',
                    code: 422,
                    context: [
                        'file_size' => $file->getSize(),
                        'max_size' => config('media.max_file_size'),
                        'user_id' => auth()->id(),
                    ]
                );
            }
            
            // Process upload
            $media = Media::create([
                'filename' => $file->store('uploads'),
                'original_name' => $file->getClientOriginalName(),
                'size' => $file->getSize(),
                'mime_type' => $file->getMimeType(),
            ]);
            
            // Log successful upload
            $this->auditLogger->logEvent([
                'event' => 'media_uploaded',
                'user_id' => auth()->id(),
                'media_id' => $media->id,
                'filename' => $media->original_name,
            ]);
            
            return $media;
            
        } catch (Exception $e) {
            // Log upload failure
            $this->auditLogger->logEvent([
                'event' => 'media_upload_failed',
                'user_id' => auth()->id(),
                'filename' => $file->getClientOriginalName(),
                'error' => $e->getMessage(),
            ]);
            
            throw $e;
        }
    }
}

Testing

Running Error Handling Tests

# Run all error handling tests
php artisan test --filter=ErrorHandling

# Run specific test
php artisan test --filter=test_cms_exception_handling

# Run with coverage
php artisan test --filter=ErrorHandling --coverage

Writing Custom Tests

<?php

namespace Tests\Feature;

use ArtisanPackUI\CMSFramework\Exceptions\CMSException;
use ArtisanPackUI\CMSFramework\Services\ErrorTrackingService;

class CustomErrorHandlingTest extends TestCase
{
    public function test_custom_error_scenario(): void
    {
        // Arrange
        $service = app(ErrorTrackingService::class);
        $exception = new CMSException('Test error');
        
        // Act
        $result = $service->trackError($exception, ['test' => true]);
        
        // Assert
        $this->assertTrue($result);
        $this->assertNotNull($service->getLastTrackedErrorId());
    }
}

Best Practices

1. Use Domain-Specific Exceptions

Always use the appropriate domain-specific exception rather than generic exceptions:

// ❌ Don't do this
throw new Exception('User not found');

// ✅ Do this
throw new UserException(
    message: 'User not found',
    action: 'user_lookup',
    code: 404,
    context: ['user_id' => $userId]
);

2. Provide Rich Context

Include relevant context information with exceptions:

throw new ContentException(
    message: 'Content publication failed',
    contentId: $content->id,
    errorType: 'publication_failed',
    context: [
        'user_id' => auth()->id(),
        'content_status' => $content->status,
        'publication_date' => $content->published_at,
        'user_permissions' => auth()->user()->permissions,
    ]
);

3. Sanitize Sensitive Data

Never log sensitive information:

// ❌ Don't include passwords or tokens
$context = [
    'user_data' => $request->all(), // May contain passwords
];

// ✅ Exclude sensitive fields
$context = [
    'user_data' => $request->except(['password', 'password_confirmation', 'token']),
];

4. Use Structured Logging

Log data in a structured format for better analysis:

$logger->logStructured('info', 'User action', [
    'event' => 'content_created',
    'user_id' => auth()->id(),
    'content_id' => $content->id,
    'content_type' => $content->type,
    'timestamp' => now()->toISOString(),
]);

5. Monitor Performance

Keep error handling lightweight:

// ❌ Avoid heavy operations in error handling
catch (Exception $e) {
    $this->heavyDatabaseOperation(); // Don't do this
    throw new CMSException($e->getMessage());
}

// ✅ Keep it simple
catch (Exception $e) {
    throw new CMSException(
        message: $e->getMessage(),
        context: ['original_error' => $e->getFile() . ':' . $e->getLine()]
    );
}

Troubleshooting

Common Issues

1. Logs Not Writing

Problem: Error logs are not being written to files.

Solutions:

  • Check file permissions on log directories
  • Verify log channel configuration
  • Ensure storage/logs directory exists
  • Check disk space
# Check permissions
ls -la storage/logs/

# Create directories if missing
mkdir -p storage/logs/cms

# Set correct permissions
chmod -R 755 storage/logs/

2. Error Tracking Not Working

Problem: Errors are not being sent to external tracking services.

Solutions:

  • Verify API keys and configuration
  • Check network connectivity
  • Review rate limiting settings
  • Ensure tracking is enabled
// Check configuration
php artisan config:show cms-error-handling.tracking

3. Performance Issues

Problem: Error handling is causing performance problems.

Solutions:

  • Review error handling performance configuration
  • Reduce context data size
  • Optimize log formatters
  • Consider async processing
// Monitor performance
php artisan cms:error-logs:analyze --performance

Debug Mode

Enable debug mode for additional information:

# Enable debug mode
export CMS_ERROR_DEBUG_MODE=true

# Test error handling
php artisan cms:error-logs:test --type=cms --with-context

Log Analysis

Use the analysis command to identify issues:

# Analyze recent errors
php artisan cms:error-logs:analyze --period=1h --detailed

# Look for patterns
php artisan cms:error-logs:analyze --group-by=error_type

# Export for external analysis
php artisan cms:error-logs:analyze --export=json --output=analysis.json

For more information, see the API Documentation and Configuration Reference.