refactor: improve logging system and add deployment fixes
- Enhance logging handlers (Console, DockerJson, File, JsonFile, MultiFile) - Improve exception and line formatters - Update logger initialization and processor management - Add Ansible playbooks for staging 502 error troubleshooting - Update deployment documentation - Fix serializer and queue components - Update error kernel and queued log handler
This commit is contained in:
@@ -5,10 +5,9 @@ declare(strict_types=1);
|
||||
namespace App\Framework\Logging;
|
||||
|
||||
use App\Framework\Attributes\Singleton;
|
||||
use App\Framework\DateTime\Clock;
|
||||
use App\Framework\Logging\ValueObjects\LogContext;
|
||||
use DateMalformedStringException;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* Einfacher Logger für das Framework.
|
||||
@@ -19,12 +18,14 @@ final readonly class DefaultLogger implements Logger, SupportsChannels
|
||||
private ChannelLoggerRegistry $channelRegistry;
|
||||
|
||||
/**
|
||||
* @param Clock $clock Clock für Timestamp-Generierung
|
||||
* @param LogLevel $minLevel Minimales Level, das geloggt werden soll
|
||||
* @param array<LogHandler> $handlers Array von Log-Handlern
|
||||
* @param ProcessorManager $processorManager Processor Manager für die Verarbeitung
|
||||
* @param LogContextManager|null $contextManager Optional: Context Manager für automatische Kontext-Anreicherung
|
||||
*/
|
||||
public function __construct(
|
||||
private Clock $clock,
|
||||
private LogLevel $minLevel = LogLevel::DEBUG,
|
||||
/** @var LogHandler[] */
|
||||
private array $handlers = [],
|
||||
@@ -84,6 +85,30 @@ final readonly class DefaultLogger implements Logger, SupportsChannels
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
public function log(LogLevel $level, string $message, ?LogContext $context = null): void
|
||||
{
|
||||
$this->createAndProcessRecord($level, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loggt in einen spezifischen Channel
|
||||
*
|
||||
* @internal Wird von ChannelLogger verwendet
|
||||
*/
|
||||
public function logToChannel(LogChannel $channel, LogLevel $level, string $message, ?LogContext $context = null): void
|
||||
{
|
||||
$this->createAndProcessRecord($level, $message, $context, $channel->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt und verarbeitet einen Log-Record
|
||||
*
|
||||
* @param LogLevel $level Log-Level
|
||||
* @param string $message Log-Nachricht
|
||||
* @param LogContext|null $context Strukturierter LogContext
|
||||
* @param string|null $channel Optional: Channel-Name
|
||||
* @throws DateMalformedStringException
|
||||
*/
|
||||
private function createAndProcessRecord(LogLevel $level, string $message, ?LogContext $context = null, ?string $channel = null): void
|
||||
{
|
||||
// Wenn kein Context übergeben, leeren Context erstellen
|
||||
if ($context === null) {
|
||||
@@ -103,47 +128,8 @@ final readonly class DefaultLogger implements Logger, SupportsChannels
|
||||
message: $message,
|
||||
context: $finalContext,
|
||||
level: $level,
|
||||
timestamp: new DateTimeImmutable(timezone: new DateTimeZone('Europe/Berlin')),
|
||||
);
|
||||
|
||||
// Record durch alle Processors verarbeiten
|
||||
$processedRecord = $this->processorManager->processRecord($record);
|
||||
|
||||
// Alle Handler durchlaufen
|
||||
foreach ($this->handlers as $handler) {
|
||||
if ($handler->isHandling($processedRecord)) {
|
||||
$handler->handle($processedRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loggt in einen spezifischen Channel
|
||||
*
|
||||
* @internal Wird von ChannelLogger verwendet
|
||||
*/
|
||||
public function logToChannel(LogChannel $channel, LogLevel $level, string $message, ?LogContext $context = null): void
|
||||
{
|
||||
// Wenn kein Context übergeben, leeren Context erstellen
|
||||
if ($context === null) {
|
||||
$context = LogContext::empty();
|
||||
}
|
||||
|
||||
// Prüfen, ob Level hoch genug ist
|
||||
if ($level->isLowerThan($this->minLevel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// LogContext automatisch mit aktuellem Context anreichern
|
||||
$finalContext = $this->enrichWithCurrentContext($context);
|
||||
|
||||
// Log-Record erstellen mit Channel
|
||||
$record = new LogRecord(
|
||||
message: $message,
|
||||
context: $finalContext,
|
||||
level: $level,
|
||||
timestamp: new DateTimeImmutable(timezone: new DateTimeZone('Europe/Berlin')),
|
||||
channel: $channel->value
|
||||
timestamp: $this->clock->now(),
|
||||
channel: $channel
|
||||
);
|
||||
|
||||
// Record durch alle Processors verarbeiten
|
||||
@@ -173,75 +159,6 @@ final readonly class DefaultLogger implements Logger, SupportsChannels
|
||||
return $currentContext->merge($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Konvertiert LogContext zu Array für Legacy-Kompatibilität
|
||||
* @deprecated
|
||||
*/
|
||||
private function convertLogContextToArray(LogContext $logContext): array
|
||||
{
|
||||
$context = $logContext->structured;
|
||||
|
||||
// Tags hinzufügen
|
||||
if ($logContext->hasTags()) {
|
||||
$context['_tags'] = $logContext->tags;
|
||||
}
|
||||
|
||||
// Trace-Informationen hinzufügen
|
||||
if ($logContext->trace !== null) {
|
||||
$context['_trace_id'] = $logContext->trace->getTraceId();
|
||||
if ($activeSpan = $logContext->trace->getActiveSpan()) {
|
||||
$context['_span_id'] = $activeSpan->spanId;
|
||||
}
|
||||
}
|
||||
|
||||
// User-Kontext hinzufügen
|
||||
if ($logContext->user !== null) {
|
||||
$context['_user_id'] = $logContext->user->userId ?? null;
|
||||
}
|
||||
|
||||
// Request-Kontext hinzufügen
|
||||
if ($logContext->request !== null) {
|
||||
$context['_request_id'] = $logContext->request->requestId ?? null;
|
||||
}
|
||||
|
||||
return array_merge($context, $logContext->metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reichert LogRecord mit strukturierten Daten aus LogContext an
|
||||
*/
|
||||
private function enrichRecordWithLogContext(LogRecord $record, LogContext $logContext): LogRecord
|
||||
{
|
||||
// Tags als Extra hinzufügen
|
||||
if ($logContext->hasTags()) {
|
||||
$record->addExtra('structured_tags', $logContext->tags);
|
||||
}
|
||||
|
||||
// Trace-Kontext als Extra hinzufügen
|
||||
if ($logContext->trace !== null) {
|
||||
$record->addExtra('trace_context', [
|
||||
'trace_id' => $logContext->trace->getTraceId(),
|
||||
'active_span' => $logContext->trace->getActiveSpan()?->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
// User-Kontext als Extra hinzufügen
|
||||
if ($logContext->user !== null) {
|
||||
$record->addExtra('user_context', $logContext->user->toArray());
|
||||
}
|
||||
|
||||
// Request-Kontext als Extra hinzufügen
|
||||
if ($logContext->request !== null) {
|
||||
$record->addExtra('request_context', $logContext->request->toArray());
|
||||
}
|
||||
|
||||
// Metadaten als Extra hinzufügen
|
||||
if (! empty($logContext->metadata)) {
|
||||
$record->addExtras($logContext->metadata);
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt einen ChannelLogger für einen spezifischen Channel
|
||||
|
||||
Reference in New Issue
Block a user