addProcessor(new ExceptionEnrichmentProcessor()); $handler = new class () implements \App\Framework\Logging\LogHandler { public array $handledRecords = []; public function isHandling(\App\Framework\Logging\LogRecord $record): bool { return true; } public function handle(\App\Framework\Logging\LogRecord $record): void { $this->handledRecords[] = $record; } }; $logger = new DefaultLogger( minLevel: LogLevel::DEBUG, handlers: [$handler], processorManager: $processorManager ); // Simulate real application scenario with nested exceptions try { try { throw new RuntimeException('Database connection failed'); } catch (RuntimeException $e) { throw new Exception('User registration failed', 500, $e); } } catch (Exception $exception) { // Log the exception with context $context = LogContext::withData([ 'user_email' => 'test@example.com', 'action' => 'registration', 'exception' => $exception, ])->addTags('error', 'registration'); $logger->error('User registration failed with exception', $context); } // Verify enrichment worked expect($handler->handledRecords)->toHaveCount(1); $record = $handler->handledRecords[0]; $extras = $record->getExtras(); // Verify basic exception info expect($extras['exception_class'])->toBe(Exception::class); expect($extras['exception_message'])->toBe('User registration failed'); expect($extras['exception_code'])->toBe(500); expect($extras['exception_severity'])->toBe('unknown'); // Verify stack trace expect($extras['stack_trace'])->toBeArray(); expect($extras['stack_trace_short'])->toBeString(); // Verify previous exceptions expect($extras['previous_exceptions'])->toBeArray(); expect($extras['previous_exceptions'])->toHaveCount(1); expect($extras['previous_exceptions'][0]['class'])->toBe(RuntimeException::class); expect($extras['previous_exceptions'][0]['message'])->toBe('Database connection failed'); // Verify exception hash for grouping expect($extras['exception_hash'])->toBeString(); expect($extras['exception_hash'])->toHaveLength(8); echo "\nšŸŽ‰ Exception Enrichment Working! Enhanced exception details:\n"; echo " Exception: {$extras['exception_class']}\n"; echo " Severity: {$extras['exception_severity']}\n"; echo " Hash: {$extras['exception_hash']}\n"; echo " Previous: " . count($extras['previous_exceptions']) . " exception(s)\n"; echo " Short trace: {$extras['stack_trace_short']}\n"; }); /** * Demonstrates processor integration with channel logging */ it('enriches exceptions in channel logging', function () { $processorManager = new ProcessorManager(); $processorManager = $processorManager->addProcessor(new ExceptionEnrichmentProcessor()); $handler = new class () implements \App\Framework\Logging\LogHandler { public array $handledRecords = []; public function isHandling(\App\Framework\Logging\LogRecord $record): bool { return true; } public function handle(\App\Framework\Logging\LogRecord $record): void { $this->handledRecords[] = $record; } }; $logger = new DefaultLogger( handlers: [$handler], processorManager: $processorManager ); // Use security channel with exception $securityException = new RuntimeException('Authentication failed'); $context = LogContext::withData([ 'ip_address' => '192.168.1.100', 'user_agent' => 'Mozilla/5.0...', 'exception' => $securityException, ])->addTags('security', 'auth_failure'); $logger->security->warning('Security breach detected', $context); // Verify channel and enrichment $record = $handler->handledRecords[0]; expect($record->getChannel())->toBe('security'); expect($record->getExtra('exception_class'))->toBe(RuntimeException::class); expect($record->getExtra('exception_severity'))->toBe('medium'); });