serializer = $prettyPrint ? JsonSerializer::pretty() : JsonSerializer::compact(); // Environment Detection (production, staging, development) $this->environment = $env?->getString('APP_ENV', 'production') ?? 'production'; // Host Detection $this->host = gethostname() ?: 'unknown'; // Service Name (default: app name from env) $this->serviceName = $serviceName ?? $env?->getString('APP_NAME', 'app') ?? 'app'; // Redactor Setup: Auto-select based on environment if not provided if ($redactSensitiveData && $redactor === null) { $this->redactor = match ($this->environment) { 'production' => SensitiveDataRedactor::production(), 'testing' => SensitiveDataRedactor::testing(), default => SensitiveDataRedactor::development(), }; } else { $this->redactor = $redactor; } } public function __invoke(LogRecord $record): string { $data = $this->formatRecord($record); return $this->serializer->serialize($data); } /** * Formatiert LogRecord zu einheitlichem Array für JSON-Serialisierung * * @return array */ private function formatRecord(LogRecord $record): array { $timestamp = $record->timestamp->format('c'); // ISO 8601 $data = [ // Standard Log Fields 'timestamp' => $timestamp, '@timestamp' => $timestamp, // Elasticsearch convention 'level' => $record->level->getName(), 'level_value' => $record->level->value, 'severity' => $record->level->toRFC5424(), // RFC 5424 (0-7) 'channel' => $record->channel, 'message' => $this->redactMessage($record->message), // Infrastructure Fields (for log aggregators) 'environment' => $this->environment, 'host' => $this->host, 'service' => $this->serviceName, ]; // Correlation ID (top-level für bessere Filterbarkeit) if ($record->context->hasCorrelationId()) { $data['correlation.id'] = $record->context->getCorrelationId()->toString(); } // Context hinzufügen mit optionalem Flatten $context = $record->context->toArray(); if ($this->flattenContext && isset($context['structured'])) { // Flatten: Nur strukturierte Daten für bessere Aggregator-Kompatibilität $data['context'] = $this->redactData($context['structured']); } else { // Raw: Gesamtes LogContext-Array $data['context'] = $this->redactData($context); } // Extras hinzufügen (wenn aktiviert und vorhanden) if ($this->includeExtras && !empty($record->extra)) { $data['extra'] = $this->redactData($record->extra); } return $data; } /** * Redacted Message falls Redactor aktiviert */ private function redactMessage(string $message): string { if ($this->redactor === null) { return $message; } return $this->redactor->redactString($message); } /** * Redacted Array-Daten falls Redactor aktiviert * * @param array $data * @return array */ private function redactData(array $data): array { if ($this->redactor === null) { return $data; } return $this->redactor->redact($data); } }