Files
michaelschiemer/backups/docs-backup-20250731125004/framework/error-reporting.md
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

12 KiB

Error Reporting & Analytics

Das Error Reporting System bietet strukturierte Fehlerberichterstattung und erweiterte Analytics für das Framework. Es erfasst, analysiert und visualisiert Fehler mit umfassendem Kontext für bessere Debugging- und Monitoring-Möglichkeiten.

Überblick

Das System implementiert folgende Funktionen:

  • Strukturierte Fehlerberichte - Umfassende Kontext-Erfassung
  • Analytics Engine - Trend-Analyse und Anomalie-Erkennung
  • Predictive Insights - Vorhersagen und Empfehlungen
  • Context Processors - Automatische Anreicherung mit Request/User-Kontext
  • Storage Interface - Flexible Speicher-Implementierungen
  • Console Commands - Management und Monitoring Tools

Basic Usage

Error Reporter

use App\Framework\ErrorReporting\ErrorReporter;

$reporter = $container->get(ErrorReporter::class);

// Report an exception
$reportId = $reporter->reportThrowable($exception);

// Report manual error
$reportId = $reporter->reportError('error', 'Something went wrong', [
    'user_action' => 'delete_file',
    'file_id' => 123
]);

Mit Request Context

$contextualReporter = $reporter->withRequestContext(
    method: 'POST',
    route: '/api/users',
    requestId: $requestId,
    userAgent: $userAgent,
    ipAddress: $clientIp
);

$reportId = $contextualReporter->reportThrowable($exception);

Mit User Context

$userReporter = $reporter->withUserContext(
    userId: $user->getId(),
    sessionId: $session->getId()
);

$reportId = $userReporter->reportError('warning', 'User action failed');

Error Report Structure

$report = ErrorReport::fromThrowable($exception)
    ->withUser($userId, $sessionId)
    ->withRequest($method, $route, $requestId, $userAgent, $ipAddress)
    ->withPerformance($executionTime, $memoryUsage)
    ->withTags(['api', 'payment'])
    ->withBreadcrumbs($breadcrumbs)
    ->withCustomData(['order_id' => 12345]);

Report Properties

  • Basic Info: ID, timestamp, level, message, exception class
  • Location: File, line, stack trace
  • User Context: User ID, session ID
  • Request Context: Route, method, IP, user agent, request data
  • Performance: Execution time, memory usage
  • Metadata: Tags, breadcrumbs, custom data, environment info
  • Analytics: Fingerprint, severity level

Analytics Engine

Anomalie-Erkennung

use App\Framework\ErrorReporting\Analytics\ErrorAnalyticsEngine;

$analytics = $container->get(ErrorAnalyticsEngine::class);

$from = new DateTimeImmutable('-24 hours');
$to = new DateTimeImmutable();

// Detect anomalies and spikes
$anomalies = $analytics->detectAnomalies($from, $to);

foreach ($anomalies as $anomaly) {
    echo "Anomaly detected: {$anomaly['type']} at {$anomaly['period']}\n";
    echo "Count: {$anomaly['count']} (expected: {$anomaly['expected']})\n";
    echo "Z-Score: {$anomaly['z_score']}\n";
}

Error Velocity

// Calculate rate of change
$velocity = $analytics->calculateErrorVelocity($from, $to);

$latest = end($velocity);
echo "Latest trend: {$latest['direction']} ({$latest['velocity_percent']}%)\n";

Pattern Analysis

$patterns = $analytics->identifyPatterns($from, $to);

// Route correlations
foreach ($patterns['route_correlations'] as $correlation) {
    echo "Route {$correlation['route']}: {$correlation['total_errors']} errors\n";
    echo "Clustered periods: {$correlation['clustered_periods']}\n";
}

// Time patterns
$timePatterns = $patterns['time_patterns'];
echo "Peak hour: {$timePatterns['peak_hour']}\n";
echo "Peak day: {$timePatterns['peak_day']}\n";

Predictive Insights

$predictions = $analytics->generatePredictiveInsights($from, $to);

$trend = $predictions['trend_prediction'];
echo "Trend: {$trend['trend']} (slope: {$trend['slope']})\n";

foreach ($trend['predictions'] as $prediction) {
    echo "Period +{$prediction['period']}: ~{$prediction['predicted_count']} errors\n";
}

$risk = $predictions['risk_assessment'];
echo "Risk level: {$risk['level']} (factor: {$risk['risk_factor']})\n";

Health Report

$healthReport = $analytics->generateHealthReport($from, $to);

echo "Health Score: {$healthReport['health_score']}/100\n";

// Impact analysis
$impact = $healthReport['impact'];
echo "Affected users: {$impact['user_impact']['affected_users']}\n";
echo "Critical errors: {$impact['business_impact']['critical_errors']}\n";

// Recommendations
foreach ($healthReport['predictions']['recommendations'] as $rec) {
    echo "[{$rec['priority']}] {$rec['message']}\n";
}

Search & Filtering

use App\Framework\ErrorReporting\ErrorReportCriteria;

// Recent critical errors
$criteria = ErrorReportCriteria::critical();
$reports = $reporter->findReports($criteria);

// Errors by user
$criteria = ErrorReportCriteria::byUser('user123');
$reports = $reporter->findReports($criteria);

// Complex search
$criteria = ErrorReportCriteria::recent(48) // Last 48 hours
    ->withLevels(['error', 'critical'])
    ->withEnvironment('production')
    ->withPagination(50, 0);

$reports = $reporter->findReports($criteria);

Search Criteria Options

$criteria = new ErrorReportCriteria(
    from: $fromDate,
    to: $toDate,
    levels: ['error', 'critical'],
    exceptions: ['DatabaseException', 'PaymentException'],
    routes: ['/api/payment', '/api/orders'],
    methods: ['POST', 'PUT'],
    userId: 'user123',
    environment: 'production',
    tags: ['payment', 'critical'],
    search: 'connection timeout',
    fingerprint: 'abc123',
    minSeverity: 2,
    maxSeverity: 4,
    limit: 100,
    offset: 0,
    orderBy: 'timestamp',
    orderDir: 'DESC'
);

Context Processors

Request Context Processor

Automatische Anreicherung mit HTTP Request Informationen:

  • Method, Route, User-Agent, IP-Adresse
  • Request Data (GET, POST, JSON) - sanitized
  • Execution Time, Memory Usage
  • Tags (API, AJAX, Method)

User Context Processor

Automatische Anreicherung mit User Informationen:

  • User ID aus Session
  • Session ID
  • User Breadcrumbs
  • Tags (authenticated/anonymous)
use App\Framework\ErrorReporting\Processors\UserContextProcessor;

// Add breadcrumb from application code
UserContextProcessor::addBreadcrumb(
    message: 'User clicked delete button',
    category: 'user_action',
    level: 'info',
    data: ['file_id' => 123]
);

HTTP Middleware

Automatische Fehlerberichterstattung für HTTP Requests:

// Automatically registered via initializer
$app->addMiddleware(ErrorReportingMiddleware::class);

Das Middleware:

  • Fängt alle ungefangenen Exceptions ab
  • Fügt Request-Kontext automatisch hinzu
  • Sanitized Request-Daten
  • Bestimmt Client IP korrekt (X-Forwarded-For, etc.)

Console Commands

Statistiken anzeigen

# Last 24 hours (default)
php console.php errors:stats

# Last 48 hours  
php console.php errors:stats 48

Zeigt:

  • Total/Unique Errors
  • Critical Error Count
  • Error Rate & Health Score
  • Errors by Level
  • Top Exceptions & Routes
  • Insights & Recommendations

Advanced Analytics

# Advanced analytics report
php console.php errors:analytics 24

Zeigt:

  • Anomaly Detection
  • Error Velocity
  • Pattern Analysis
  • Predictive Insights

Health Report

# Comprehensive health report
php console.php errors:health 24

Zeigt:

  • Overall Health Score
  • Key Metrics
  • Impact Analysis
  • Recommendations

Search Errors

# Search by term
php console.php errors:search "database connection"

Show Error Details

# Show detailed error report
php console.php errors:show <report-id>

Cleanup

# Delete errors older than 30 days (default)
php console.php errors:cleanup

# Delete errors older than 7 days
php console.php errors:cleanup 7

Environment Configuration

# Enable/disable error reporting
ERROR_REPORTING_ENABLED=true

# Enable async processing via queue
ERROR_REPORTING_ASYNC=true

# Filter levels (comma-separated)
ERROR_REPORTING_FILTER_LEVELS=error,critical,alert,emergency

Database Schema

Das System benötigt die error_reports Tabelle:

php console.php db:migrate

Die Migration erstellt eine optimierte Tabelle mit:

  • Primary Key: String ID (32 chars)
  • Indexes für häufige Queries
  • JSON Felder für flexible Daten
  • Analytics-Felder (fingerprint, severity_level)

Storage Interface

Custom Storage Implementierungen möglich:

use App\Framework\ErrorReporting\Storage\ErrorReportStorageInterface;

class RedisErrorReportStorage implements ErrorReportStorageInterface
{
    public function store(ErrorReport $report): void
    {
        // Custom implementation
    }
    
    // ... other methods
}

// In initializer
$container->bind(ErrorReportStorageInterface::class, RedisErrorReportStorage::class);

Best Practices

1. Structured Error Messages

// Good - structured context
$reporter->reportError('error', 'Payment processing failed', [
    'payment_id' => $paymentId,
    'amount' => $amount,
    'currency' => $currency,
    'gateway_response' => $gatewayResponse
]);

// Avoid - unstructured message
$reporter->reportError('error', "Payment $paymentId failed for $amount $currency");

2. Appropriate Log Levels

// Critical system failures
$reporter->reportThrowable($exception, 'critical');

// Business logic errors
$reporter->reportThrowable($exception, 'error');

// Recoverable issues
$reporter->reportError('warning', 'Deprecated API used');

// Development info
$reporter->reportError('info', 'Cache miss occurred');

3. Sensitive Data Handling

// Data is automatically sanitized by processors
// But be explicit about sensitive data
$reporter->reportError('error', 'Authentication failed', [
    'username' => $username,
    'ip_address' => $ip,
    // Don't include: password, tokens, etc.
]);

4. Custom Tags for Filtering

$report = ErrorReport::fromThrowable($exception)
    ->withTags(['payment', 'external_api', 'critical']);

5. Breadcrumbs for Context

// Add breadcrumbs throughout user journey
UserContextProcessor::addBreadcrumb('User logged in');
UserContextProcessor::addBreadcrumb('Started checkout process');
UserContextProcessor::addBreadcrumb('Selected payment method', 'action', 'info', [
    'method' => 'credit_card'
]);

// Error report will include full journey

Performance Considerations

  1. Async Processing - Enable für Production (ERROR_REPORTING_ASYNC=true)
  2. Data Sanitization - Automatic für Request Data
  3. Storage Optimization - Indexes für häufige Queries
  4. Cleanup Strategy - Regular cleanup alter Reports
  5. Memory Usage - Limited Context Data Size

Security Considerations

  1. Data Sanitization - Sensitive Data wird automatisch entfernt
  2. Access Control - Console Commands benötigen entsprechende Rechte
  3. Storage Security - Database Access Controls
  4. IP Address Handling - Respects Privacy Regulations
  5. Session Security - Nur Session IDs, keine Session Daten

Integration Examples

Mit Custom Exception Handler

class CustomExceptionHandler
{
    public function __construct(
        private ErrorReporter $reporter
    ) {}
    
    public function handle(Throwable $exception): void
    {
        // Report the error
        $this->reporter->reportThrowable($exception);
        
        // Continue with normal error handling
        $this->originalHandler->handle($exception);
    }
}

Mit Business Logic

class PaymentService
{
    public function processPayment(Payment $payment): PaymentResult
    {
        try {
            return $this->gateway->process($payment);
        } catch (PaymentException $e) {
            // Report with business context
            $this->reporter->reportThrowable($e, 'error', [
                'payment_id' => $payment->getId(),
                'amount' => $payment->getAmount(),
                'gateway' => $this->gateway->getName(),
            ]);
            
            throw $e;
        }
    }
}

Mit Background Jobs

class EmailJob
{
    public function handle(): void
    {
        try {
            $this->sendEmails();
        } catch (Throwable $e) {
            $this->reporter->reportThrowable($e, 'error', [
                'job' => 'email_sending',
                'batch_size' => count($this->emails),
            ]);
            
            throw $e;
        }
    }
}