refactor(console, id, config): Dialog mode in Console, consolidated id modul, added config support for ini directives

This commit is contained in:
2025-11-04 13:44:27 +01:00
parent 980714f656
commit bfce93ce77
110 changed files with 2828 additions and 774 deletions

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace App\Framework\Logging\Formatter;
use App\Framework\Console\CliSapi;
use App\Framework\Console\ConsoleStyle;
use App\Framework\Console\TerminalDetector;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
@@ -17,6 +20,21 @@ final readonly class DevelopmentFormatter implements LogFormatter
private bool $colorOutput = true
) {
}
/**
* Prüft ob Farben verwendet werden sollen (berücksichtigt Terminal-Detection)
*/
private function shouldUseColors(): bool
{
// Wenn colorOutput explizit false, keine Farben
if (!$this->colorOutput) {
return false;
}
// Prüfe Terminal-Detection mit CliSapi
$cliSapi = CliSapi::detect();
return $cliSapi->supportsColors($cliSapi->stdout);
}
public function __invoke(LogRecord $record): string
{
@@ -26,7 +44,7 @@ final readonly class DevelopmentFormatter implements LogFormatter
$message = $record->getMessage();
// Color coding for levels
$levelString = $this->colorOutput ? $this->colorizeLevel($level) : $level->getName();
$levelString = $this->shouldUseColors() ? $this->colorizeLevel($level) : $level->getName();
$output = sprintf(
"%s [%s] %s.%s: %s\n",
@@ -54,20 +72,11 @@ final readonly class DevelopmentFormatter implements LogFormatter
private function colorizeLevel(LogLevel $level): string
{
if (! $this->colorOutput) {
return $level->getName();
}
return match($level) {
LogLevel::DEBUG => "\033[36m" . $level->getName() . "\033[0m", // Cyan
LogLevel::INFO => "\033[32m" . $level->getName() . "\033[0m", // Green
LogLevel::NOTICE => "\033[34m" . $level->getName() . "\033[0m", // Blue
LogLevel::WARNING => "\033[33m" . $level->getName() . "\033[0m", // Yellow
LogLevel::ERROR => "\033[31m" . $level->getName() . "\033[0m", // Red
LogLevel::CRITICAL => "\033[35m" . $level->getName() . "\033[0m", // Magenta
LogLevel::ALERT => "\033[41m" . $level->getName() . "\033[0m", // Red background
LogLevel::EMERGENCY => "\033[41;37m" . $level->getName() . "\033[0m", // Red bg, white text
};
// Verwende LogLevel::getConsoleColor() und ConsoleStyle statt hardcoded ANSI-Codes
$consoleColor = $level->getConsoleColor();
$style = ConsoleStyle::create(color: $consoleColor);
return $style->apply($level->getName());
}
private function formatContext(array $context): string

View File

@@ -4,15 +4,34 @@ declare(strict_types=1);
namespace App\Framework\Logging\Formatter;
use App\Framework\Console\CliSapi;
use App\Framework\Console\ConsoleStyle;
use App\Framework\Console\TerminalDetector;
use App\Framework\Logging\LogRecord;
final readonly class LineFormatter implements LogFormatter
{
public function __construct(
private string $format = "[{timestamp}] {channel}.{level}: {message} {context}",
private string $timestampFormat = 'Y-m-d H:i:s'
private string $timestampFormat = 'Y-m-d H:i:s',
private bool $colorOutput = false
) {
}
/**
* Prüft ob Farben verwendet werden sollen (berücksichtigt Terminal-Detection)
*/
private function shouldUseColors(): bool
{
// Wenn colorOutput explizit false, keine Farben
if (!$this->colorOutput) {
return false;
}
// Prüfe Terminal-Detection mit CliSapi (für stderr, da Web-Requests auf stderr loggen)
$cliSapi = CliSapi::detect();
return $cliSapi->supportsColors($cliSapi->stderr);
}
public function __invoke(LogRecord $record): string
{
@@ -33,11 +52,17 @@ final readonly class LineFormatter implements LogFormatter
? "[{$record->getChannel()}] "
: '';
// Level-String mit optionalen Farben
$levelName = $record->level->getName();
$coloredLevel = $this->shouldUseColors()
? $this->colorizeLevel($record->level)
: $levelName;
$replacements = [
'{timestamp}' => $record->getFormattedTimestamp($this->timestampFormat),
'{channel}' => $record->channel ?? 'app',
'{level}' => $record->level->getName(),
'{level_name}' => $record->level->getName(),
'{level}' => $coloredLevel,
'{level_name}' => $coloredLevel,
'{message}' => $record->message,
'{context}' => $contextString,
'{request_id}' => $requestId,
@@ -45,4 +70,16 @@ final readonly class LineFormatter implements LogFormatter
return strtr($this->format, $replacements);
}
/**
* Färbt den Level-String basierend auf LogLevel
*/
private function colorizeLevel(\App\Framework\Logging\LogLevel $level): string
{
// Verwende LogLevel::getConsoleColor() und ConsoleStyle statt hardcoded ANSI-Codes
$consoleColor = $level->getConsoleColor();
$style = ConsoleStyle::create(color: $consoleColor);
return $style->apply($level->getName());
}
}

View File

@@ -0,0 +1,190 @@
<?php
declare(strict_types=1);
namespace App\Framework\Logging;
use App\Framework\Config\EnvKey;
use App\Framework\Config\Environment;
use App\Framework\Config\TypedConfiguration;
use App\Framework\Console\CliSapi;
use App\Framework\Console\TerminalDetector;
use App\Framework\Core\PathProvider;
use App\Framework\Logging\Formatter\DevelopmentFormatter;
use App\Framework\Logging\Formatter\LineFormatter;
use App\Framework\Logging\Handlers\ConsoleHandler;
use App\Framework\Logging\Handlers\DockerJsonHandler;
use App\Framework\Logging\Handlers\FileHandler;
use App\Framework\Logging\Handlers\MultiFileHandler;
use App\Framework\Queue\Queue;
/**
* Factory für Log-Handler-Erstellung basierend auf Umgebung und Konfiguration.
*/
final readonly class HandlerFactory
{
/**
* Erstellt alle Handler basierend auf der Umgebung
*
* @param TypedConfiguration $config
* @param Environment $env
* @param LogConfig $logConfig
* @param PathProvider $pathProvider
* @param LogLevel $minLevel
* @param Queue $queue
* @return array<LogHandler>
*/
public function createHandlers(
TypedConfiguration $config,
Environment $env,
LogConfig $logConfig,
PathProvider $pathProvider,
LogLevel $minLevel,
Queue $queue
): array {
$handlers = [];
// Console/Docker Logging Handler - für CLI und Web-Requests
if (PHP_SAPI === 'cli') {
// CLI: Docker JSON oder Console Handler
$handlers[] = $this->createCliHandler($config, $env, $minLevel);
} else {
// Web-Requests: Console Handler auf stderr mit intelligenter Formatter-Auswahl
$cliSapi = CliSapi::detect();
$colorOutput = $this->determineColorOutput($env, $cliSapi->stderr);
$handlers[] = $this->createWebHandler($minLevel, $colorOutput);
}
// MultiFileHandler für automatisches Channel-Routing
$multiFileFormatter = new LineFormatter();
$handlers[] = new MultiFileHandler(
$logConfig,
$pathProvider,
$multiFileFormatter,
$minLevel,
0644
);
// Fallback FileHandler für Kompatibilität (nur für 'app' Channel ohne Channel-Info)
$fileFormatter = new LineFormatter(
format: 'Line Formatter: [{timestamp}] [{level_name}] {request_id}{channel}{message}',
timestampFormat: 'Y-m-d H:i:s'
);
$handlers[] = new FileHandler(
$fileFormatter,
$logConfig->getLogPath('app'),
$minLevel,
0644,
null,
$pathProvider
);
return $handlers;
}
/**
* Erstellt den CLI-Handler (Docker JSON oder Console)
*/
private function createCliHandler(
TypedConfiguration $config,
Environment $env,
LogLevel $minLevel
): LogHandler {
// Prüfe ob wir in Docker laufen (für strukturierte JSON-Logs)
$inDocker = file_exists('/.dockerenv') || getenv('DOCKER_CONTAINER') === 'true';
if ($inDocker) {
if ($config->app->isProduction()) {
// Production Docker: Compact JSON für Log-Aggregatoren mit Redaction
return new DockerJsonHandler(
env: $env,
minLevel: $minLevel,
redactSensitiveData: true // Auto-redact in Production
);
} else {
// Development Docker: Pretty JSON für bessere Lesbarkeit
return new DockerJsonHandler(
env: $env,
serviceName: $config->app->name ?? 'app',
minLevel: $minLevel,
prettyPrint: true, // Pretty-print für Development
redactSensitiveData: false // Keine Redaction in Development für Debugging
);
}
} else {
// Lokale Entwicklung: Console Handler mit intelligenter Formatter-Auswahl
$cliSapi = CliSapi::detect();
$colorOutput = $this->determineColorOutput($env, $cliSapi->stdout);
return $this->createCliConsoleHandler($minLevel, $colorOutput);
}
}
/**
* Erstellt einen Web-Request ConsoleHandler mit intelligenter Formatter-Auswahl
*/
private function createWebHandler(LogLevel $minLevel, bool $colorOutput): ConsoleHandler
{
$developmentFormatter = new DevelopmentFormatter(
includeStackTrace: true,
colorOutput: $colorOutput
);
$lineFormatter = new LineFormatter(
colorOutput: $colorOutput
);
// Intelligente Formatter-Auswahl: Array mit beiden Formattern
return new ConsoleHandler(
[
'development' => $developmentFormatter,
'line' => $lineFormatter,
],
$minLevel,
debugOnly: false
);
}
/**
* Erstellt einen CLI ConsoleHandler mit intelligenter Formatter-Auswahl
*/
private function createCliConsoleHandler(LogLevel $minLevel, bool $colorOutput): ConsoleHandler
{
$developmentFormatter = new DevelopmentFormatter(
includeStackTrace: true,
colorOutput: $colorOutput
);
$lineFormatter = new LineFormatter(
colorOutput: $colorOutput
);
// Intelligente Formatter-Auswahl: Array mit beiden Formattern
return new ConsoleHandler(
[
'development' => $developmentFormatter,
'line' => $lineFormatter,
],
$minLevel
);
}
/**
* Bestimmt ob Farb-Output aktiviert werden soll
*
* @param Environment $env Environment für Konfiguration
* @param \App\Framework\Console\ValueObjects\TerminalStream $stream Terminal Stream für Terminal-Detection
* @return bool True wenn Farben aktiviert werden sollen
*/
private function determineColorOutput(Environment $env, \App\Framework\Console\ValueObjects\TerminalStream $stream): bool
{
$colorConfig = $env->get(EnvKey::LOG_COLOR_OUTPUT, 'auto');
return match (strtolower((string) $colorConfig)) {
'true', '1', 'yes', 'on' => true,
'false', '0', 'no', 'off' => false,
default => TerminalDetector::supportsColors($stream), // 'auto' oder default
};
}
}

View File

@@ -5,6 +5,8 @@ declare(strict_types=1);
namespace App\Framework\Logging\Handlers;
use App\Framework\Logging\LogHandler;
use App\Framework\Logging\Formatter\DevelopmentFormatter;
use App\Framework\Logging\Formatter\LineFormatter;
use App\Framework\Logging\Formatter\LogFormatter;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
@@ -12,6 +14,10 @@ use App\Framework\Logging\LogRecord;
/**
* Handler für die Ausgabe von Log-Einträgen in der Konsole.
*
* Unterstützt intelligente Formatter-Auswahl basierend auf LogLevel und Context:
* - ERROR/CRITICAL/ALERT/EMERGENCY oder Exception → DevelopmentFormatter (detailliert)
* - DEBUG/INFO/NOTICE/WARNING → LineFormatter (kompakt)
*
* Bei CLI: Nutzt stderr für WARNING+ und stdout für niedrigere Levels.
* Bei Web-Requests: Alle Logs gehen auf stderr (POSIX-konform, Docker-kompatibel).
*/
@@ -28,26 +34,53 @@ class ConsoleHandler implements LogHandler
private bool $debugOnly;
/**
* @var LogFormatter Formatter für die Log-Ausgabe
* @var LogFormatter|null Formatter für die Log-Ausgabe (bei einfachem Modus)
*/
private LogFormatter $formatter;
private ?LogFormatter $formatter = null;
/**
* @var DevelopmentFormatter|null Formatter für detaillierte Ausgabe (bei intelligentem Modus)
*/
private ?DevelopmentFormatter $developmentFormatter = null;
/**
* @var LineFormatter|null Formatter für kompakte Ausgabe (bei intelligentem Modus)
*/
private ?LineFormatter $lineFormatter = null;
/**
* @var bool Ob intelligente Formatter-Auswahl aktiviert ist
*/
private bool $intelligentSelection;
/**
* Erstellt einen neuen ConsoleHandler
*
* @param LogFormatter $formatter Formatter für die Log-Ausgabe
* @param LogFormatter|array{development: DevelopmentFormatter, line: LineFormatter}|null $formatter
* Einzelner Formatter (rückwärtskompatibel) oder Array mit 'development' und 'line' Formattern für intelligente Auswahl
* @param LogLevel|int $minLevel Minimales Level, ab dem dieser Handler aktiv wird
* @param bool $debugOnly Ob der Handler nur im Debug-Modus aktiv ist
* @param LogLevel $stderrLevel Level ab dem stderr verwendet wird (default: WARNING)
*/
public function __construct(
LogFormatter $formatter,
LogFormatter|array|null $formatter = null,
LogLevel|int $minLevel = LogLevel::DEBUG,
bool $debugOnly = true,
private readonly LogLevel $stderrLevel = LogLevel::WARNING,
) {
$this->formatter = $formatter;
$this->minLevel = $minLevel instanceof LogLevel ? $minLevel : LogLevel::fromValue($minLevel);
$this->debugOnly = $debugOnly;
// Intelligente Formatter-Auswahl wenn Array übergeben wird
if (is_array($formatter)) {
$this->intelligentSelection = true;
$this->developmentFormatter = $formatter['development'] ?? null;
$this->lineFormatter = $formatter['line'] ?? null;
} else {
// Rückwärtskompatibel: Einzelner Formatter
$this->intelligentSelection = false;
$this->formatter = $formatter;
}
}
/**
@@ -68,8 +101,11 @@ class ConsoleHandler implements LogHandler
*/
public function handle(LogRecord $record): void
{
// Formatter auswählen (intelligent oder einfach)
$formatter = $this->selectFormatter($record);
// Formatter verwenden für Formatierung
$formatted = ($this->formatter)($record);
$formatted = $formatter($record);
// Formatter gibt immer string zurück für Console
$output = is_string($formatted)
@@ -96,9 +132,57 @@ class ConsoleHandler implements LogHandler
}
/**
* Gibt den Formatter zurück
* Wählt den passenden Formatter basierend auf LogLevel und Context
*/
public function getFormatter(): LogFormatter
private function selectFormatter(LogRecord $record): LogFormatter
{
// Wenn kein intelligenter Modus, verwende den einzelnen Formatter
if (!$this->intelligentSelection) {
if ($this->formatter === null) {
throw new \RuntimeException('ConsoleHandler: No formatter configured');
}
return $this->formatter;
}
// Prüfe ob Exception vorhanden ist
if ($this->hasException($record)) {
return $this->developmentFormatter ?? $this->lineFormatter ?? throw new \RuntimeException('ConsoleHandler: No formatter configured');
}
// Für ERROR, CRITICAL, ALERT, EMERGENCY: DevelopmentFormatter (detailliert)
if ($record->level->value >= LogLevel::ERROR->value) {
return $this->developmentFormatter ?? $this->lineFormatter ?? throw new \RuntimeException('ConsoleHandler: No formatter configured');
}
// Für DEBUG, INFO, NOTICE, WARNING: LineFormatter (kompakt)
return $this->lineFormatter ?? $this->developmentFormatter ?? throw new \RuntimeException('ConsoleHandler: No formatter configured');
}
/**
* Prüft ob der LogRecord eine Exception enthält
*/
private function hasException(LogRecord $record): bool
{
// Prüfe in extras
if ($record->hasExtra('exception_class') || $record->hasExtra('exception')) {
return true;
}
// Prüfe in context
$context = $record->getContext();
if (isset($context['exception']) || isset($context['exception_class'])) {
return true;
}
return false;
}
/**
* Gibt den Formatter zurück (rückwärtskompatibel)
*
* @deprecated Verwende selectFormatter() für intelligente Auswahl
*/
public function getFormatter(): ?LogFormatter
{
return $this->formatter;
}

View File

@@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Framework\Logging;
use App\Framework\DateTime\Clock;
use App\Framework\DateTime\SystemClock;
/**
* Factory für Logger-Instanzen.
*
* @deprecated Verwende stattdessen Dependency Injection. Der Logger wird automatisch über LoggerInitializer erstellt.
* Diese Klasse wird nur noch für Legacy-Code verwendet und sollte nicht in neuem Code genutzt werden.
*/
final class LoggerFactory
{
private static ?DefaultLogger $defaultLogger = null;
/**
* Erzeugt einen neuen Logger mit optionalen Einstellungen.
*
* @deprecated Verwende stattdessen Dependency Injection. Der Logger wird automatisch über LoggerInitializer erstellt.
*/
public static function create(
?Clock $clock = null,
LogLevel|int $minLevel = LogLevel::DEBUG,
array $handlers = []
): DefaultLogger {
$clock ??= new SystemClock();
return new DefaultLogger($clock, $minLevel, $handlers);
}
/**
* Gibt den Standard-Logger zurück oder erstellt ihn, falls er noch nicht existiert.
*
* @deprecated Verwende stattdessen Dependency Injection. Der Logger wird automatisch über LoggerInitializer erstellt.
*/
public static function getDefaultLogger(): DefaultLogger
{
if (self::$defaultLogger === null) {
$debug = filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN);
$minLevel = $debug ? LogLevel::DEBUG : LogLevel::INFO;
self::$defaultLogger = self::create(null, $minLevel);
}
return self::$defaultLogger;
}
/**
* Setzt einen benutzerdefinierten Logger als Standard-Logger.
*
* @deprecated Verwende stattdessen Dependency Injection.
*/
public static function setDefaultLogger(DefaultLogger $logger): void
{
self::$defaultLogger = $logger;
}
}

View File

@@ -11,17 +11,7 @@ use App\Framework\Core\PathProvider;
use App\Framework\DateTime\Clock;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Logging\Formatter\DevelopmentFormatter;
use App\Framework\Logging\Formatter\LineFormatter;
use App\Framework\Logging\Handlers\ConsoleHandler;
use App\Framework\Logging\Handlers\DockerJsonHandler;
use App\Framework\Logging\Handlers\FileHandler;
use App\Framework\Logging\Handlers\MultiFileHandler;
use App\Framework\Logging\Handlers\NullHandler;
use App\Framework\Queue\Queue;
use App\Framework\Queue\FileQueue;
use App\Framework\Redis\RedisConfig;
use App\Framework\Redis\RedisConnection;
final readonly class LoggerInitializer
{
@@ -44,8 +34,13 @@ final readonly class LoggerInitializer
$processorManager = new ProcessorManager();
$minLevel = $this->determineMinLogLevel($config);
$logConfig = $this->initializeLogConfig($pathProvider);
$queue = $this->createQueue($pathProvider);
$handlers = $this->createHandlers($config, $env, $logConfig, $pathProvider, $minLevel, $queue);
$queueFactory = new QueueFactory();
$queue = $queueFactory->createQueue($pathProvider, $env);
$handlerFactory = new HandlerFactory();
$handlers = $handlerFactory->createHandlers($config, $env, $logConfig, $pathProvider, $minLevel, $queue);
$contextManager = $container->get(LogContextManager::class);
$clock = $container->get(Clock::class);
@@ -113,117 +108,4 @@ final readonly class LoggerInitializer
return $logConfig;
}
/**
* Erstellt die Queue für asynchrones Logging
*/
private function createQueue(PathProvider $pathProvider): Queue
{
#$redisConfig = RedisConfig::fromEnvironment($env);
#$redisConnection = new RedisConnection($redisConfig, 'queue');
#return new RedisQueue($redisConnection, 'commands');
$queuePath = $pathProvider->resolvePath('storage/queue');
return new FileQueue($queuePath);
}
/**
* Erstellt alle Handler basierend auf der Umgebung
*
* @param TypedConfiguration $config
* @param Environment $env
* @param LogConfig $logConfig
* @param PathProvider $pathProvider
* @param LogLevel $minLevel
* @param Queue $queue
* @return array<LogHandler>
*/
private function createHandlers(
TypedConfiguration $config,
Environment $env,
LogConfig $logConfig,
PathProvider $pathProvider,
LogLevel $minLevel,
Queue $queue
): array {
$handlers = [];
// Console/Docker Logging Handler - für CLI und Web-Requests
if (PHP_SAPI === 'cli') {
// CLI: Docker JSON oder Console Handler
$handlers[] = $this->createCliHandler($config, $env, $minLevel);
} else {
// Web-Requests: Console Handler auf stderr
$webFormatter = new LineFormatter();
$handlers[] = new ConsoleHandler($webFormatter, $minLevel, debugOnly: false);
}
//$handlers[] = new QueuedLogHandler($queue);
// MultiFileHandler für automatisches Channel-Routing
$multiFileFormatter = new LineFormatter();
$handlers[] = new MultiFileHandler(
$logConfig,
$pathProvider,
$multiFileFormatter,
$minLevel,
0644
);
// Fallback FileHandler für Kompatibilität (nur für 'app' Channel ohne Channel-Info)
$fileFormatter = new LineFormatter(
format: 'Line Formatter: [{timestamp}] [{level_name}] {request_id}{channel}{message}',
timestampFormat: 'Y-m-d H:i:s'
);
$handlers[] = new FileHandler(
$fileFormatter,
$logConfig->getLogPath('app'),
$minLevel,
0644,
null,
$pathProvider
);
return $handlers;
}
/**
* Erstellt den CLI-Handler (Docker JSON oder Console)
*/
private function createCliHandler(
TypedConfiguration $config,
Environment $env,
LogLevel $minLevel
): LogHandler {
// Prüfe ob wir in Docker laufen (für strukturierte JSON-Logs)
$inDocker = file_exists('/.dockerenv') || getenv('DOCKER_CONTAINER') === 'true';
if ($inDocker) {
if ($config->app->isProduction()) {
// Production Docker: Compact JSON für Log-Aggregatoren mit Redaction
return new DockerJsonHandler(
env: $env,
minLevel: $minLevel,
redactSensitiveData: true // Auto-redact in Production
);
} else {
// Development Docker: Pretty JSON für bessere Lesbarkeit
return new DockerJsonHandler(
env: $env,
serviceName: $config->app->name ?? 'app',
minLevel: $minLevel,
prettyPrint: true, // Pretty-print für Development
redactSensitiveData: false // Keine Redaction in Development für Debugging
);
}
} else {
// Lokale Entwicklung: Farbige Console-Logs
$consoleFormatter = new DevelopmentFormatter(
includeStackTrace: true,
colorOutput: true
);
return new ConsoleHandler($consoleFormatter, $minLevel);
}
}
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace App\Framework\Logging;
use App\Framework\Config\Environment;
use App\Framework\Core\PathProvider;
use App\Framework\Queue\FileQueue;
use App\Framework\Queue\Queue;
/**
* Factory für Queue-Instanzen für asynchrones Logging.
*
* Unterstützt aktuell FileQueue, kann in Zukunft um RedisQueue erweitert werden.
*/
final readonly class QueueFactory
{
/**
* Erstellt eine Queue-Instanz basierend auf der Konfiguration
*
* @param PathProvider $pathProvider Path provider für File-basierte Queues
* @param Environment|null $env Optional: Environment für zukünftige Redis-Integration
* @return Queue
*/
public function createQueue(PathProvider $pathProvider, ?Environment $env = null): Queue
{
// TODO: Redis-Queue Integration wenn benötigt
// if ($env && $this->shouldUseRedisQueue($env)) {
// $redisConfig = RedisConfig::fromEnvironment($env);
// $redisConnection = new RedisConnection($redisConfig, 'queue');
// return new RedisQueue($redisConnection, 'commands');
// }
$queuePath = $pathProvider->resolvePath('storage/queue');
return new FileQueue($queuePath);
}
}

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Framework\Logging\ValueObjects;
use App\Framework\Http\ServerRequest;
use App\Framework\Ulid\Ulid;
use App\Framework\Id\Ulid\Ulid;
use Ramsey\Uuid\Uuid;
/**