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
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -1,26 +1,22 @@
<?php
declare(strict_types=1);
namespace App\Framework\Discovery;
use App\Framework\Attributes\Route;
use App\Framework\Auth\AuthMapper;
use App\Framework\Cache\Cache;
use App\Framework\CommandBus\CommandHandlerMapper;
use App\Framework\Config\Configuration;
use App\Framework\Core\AttributeMapper;
use App\Framework\Core\Events\EventHandlerMapper;
use App\Framework\Cache\CacheItem;
use App\Framework\Config\AppConfig;
use App\Framework\Config\DiscoveryConfig;
use App\Framework\Config\TypedConfiguration;
use App\Framework\Context\ExecutionContext;
use App\Framework\Core\PathProvider;
use App\Framework\Core\RouteMapper;
use App\Framework\Database\Migration\Migration;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\DateTime\Clock;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\DI\InitializerMapper;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Http\HttpMiddleware;
use App\Framework\QueryBus\QueryHandlerMapper;
use App\Framework\View\DomProcessor;
use App\Framework\View\StringProcessor;
use App\Framework\Discovery\Cache\DiscoveryCacheIdentifiers;
use App\Framework\Discovery\Factory\DiscoveryServiceFactory;
use App\Framework\Discovery\Results\DiscoveryRegistry;
/**
* Bootstrapper für den Discovery-Service
@@ -28,117 +24,143 @@ use App\Framework\View\StringProcessor;
*/
final readonly class DiscoveryServiceBootstrapper
{
public function __construct(private Container $container) {}
public function __construct(
private Container $container,
private Clock $clock
) {
}
/**
* Bootstrapt den Discovery-Service und führt die Discovery durch
*/
public function bootstrap(): DiscoveryResults
public function bootstrap(): DiscoveryRegistry
{
$pathProvider = $this->container->get(PathProvider::class);
$cache = $this->container->get(Cache::class);
$config = $this->container->get(Configuration::class);
// Discovery-Service erstellen
$discoveryService = $this->createDiscoveryService($pathProvider, $cache, $config);
// Get DiscoveryConfig if available, otherwise use defaults
$discoveryConfig = null;
if ($this->container->has(DiscoveryConfig::class)) {
$discoveryConfig = $this->container->get(DiscoveryConfig::class);
}
// Discovery durchführen
$results = $discoveryService->discover();
// Direkter Cache-Check mit expliziter toArray/fromArray Serialisierung
$defaultPaths = [$pathProvider->getSourcePath()];
$cacheKey = DiscoveryCacheIdentifiers::fullDiscoveryKey($defaultPaths);
// Ergebnisse im Container registrieren
$this->container->singleton(DiscoveryResults::class, $results);
$this->container->instance(UnifiedDiscoveryService::class, $discoveryService);
// Führe Initializers aus (Kompatibilität mit bestehendem Code)
$this->executeInitializers($results);
$cachedItem = $cache->get($cacheKey);
if ($cachedItem->isHit) {
// Versuche die gecachten Daten zu laden
$cachedRegistry = null;
#$cachedRegistry = DiscoveryRegistry::fromArray($cachedItem->value);
if ($cachedItem->value instanceof DiscoveryRegistry) {
$cachedRegistry = $cachedItem->value;
} elseif (is_array($cachedItem->value)) {
$cachedRegistry = DiscoveryRegistry::fromArray($cachedItem->value);
} elseif (is_string($cachedItem->value)) {
$cachedRegistry = DiscoveryRegistry::fromArray(json_decode($cachedItem->value, true, 512, JSON_THROW_ON_ERROR));
}
if ($cachedRegistry !== null && ! $cachedRegistry->isEmpty()) {
$this->container->singleton(DiscoveryRegistry::class, $cachedRegistry);
// Initializer-Verarbeitung für gecachte Registry
$initializerProcessor = $this->container->get(InitializerProcessor::class);
$initializerProcessor->processInitializers($cachedRegistry);
return $cachedRegistry;
}
}
// Fallback: Vollständige Discovery durchführen
$results = $this->performBootstrap($pathProvider, $cache, $discoveryConfig);
// Nach der Discovery explizit in unserem eigenen Cache-Format speichern
$cacheItem = CacheItem::forSet(
key: $cacheKey,
value: $results->toArray(),
ttl: Duration::fromHours(1)
);
$cache->set($cacheItem);
return $results;
}
/**
* Erstellt den Discovery-Service mit der richtigen Konfiguration
* Führt den Discovery-Prozess durch und verarbeitet die Ergebnisse
*/
private function performBootstrap(PathProvider $pathProvider, Cache $cache, ?DiscoveryConfig $config): DiscoveryRegistry
{
// Context-spezifische Discovery
$currentContext = ExecutionContext::detect();
$discoveryService = $this->createDiscoveryService($pathProvider, $cache, $config, $currentContext);
// Discovery durchführen
$results = $discoveryService->discover();
// Ergebnisse im Container registrieren
$this->container->singleton(DiscoveryRegistry::class, $results);
$this->container->instance(UnifiedDiscoveryService::class, $discoveryService);
// Initializer-Verarbeitung mit dedizierter Klasse
$initializerProcessor = $this->container->get(InitializerProcessor::class);
$initializerProcessor->processInitializers($results);
return $results;
}
/**
* Creates the modern discovery service with enhanced features using the new factory
*/
private function createDiscoveryService(
PathProvider $pathProvider,
Cache $cache,
Configuration $config
?DiscoveryConfig $config,
?ExecutionContext $context = null
): UnifiedDiscoveryService {
$useCache = $config->get('discovery.use_cache', true);
$showProgress = $config->get('discovery.show_progress', false);
// Attribute-Mapper aus Konfiguration oder Standard-Werte
$attributeMappers = $config->get('discovery.attribute_mappers', [
RouteMapper::class,
EventHandlerMapper::class,
\App\Framework\EventBus\EventHandlerMapper::class,
QueryHandlerMapper::class,
CommandHandlerMapper::class,
InitializerMapper::class,
AuthMapper::class,
]);
// Ziel-Interfaces aus Konfiguration oder Standard-Werte
$targetInterfaces = $config->get('discovery.target_interfaces', [
AttributeMapper::class,
HttpMiddleware::class,
DomProcessor::class,
StringProcessor::class,
Migration::class,
#Initializer::class,
]);
return new UnifiedDiscoveryService(
// Create factory
$factory = new DiscoveryServiceFactory(
$this->container,
$pathProvider,
$cache,
$attributeMappers,
$targetInterfaces,
$useCache,
$showProgress
$this->clock
);
}
/**
* Führt die gefundenen Initializers aus (Kompatibilität)
*/
private function executeInitializers(DiscoveryResults $results): void
{
$initializerResults = $results->get(Initializer::class);
// Determine environment-based factory method
$envType = 'production'; // Default fallback
#debug($initializerResults);
foreach ($initializerResults as $initializerData) {
if (!isset($initializerData['class'])) {
continue;
}
try {
$className = $initializerData['class'];
$methodName = $initializerData['method'] ?? '__invoke';
$returnType = $initializerData['return'] ?? null;
#debug($initializerData);
$instance = $this->container->invoker->invoke($className, $methodName);
// Registriere das Ergebnis im Container falls Return-Type angegeben
if ($returnType && $instance !== null) {
$this->container->instance($returnType, $instance);
}
} catch (\Throwable $e) {
debug('Fehler beim Ausführen des Initializers: ' . $e->getMessage());
error_log("Fehler beim Ausführen des Initializers {$className}: " . $e->getMessage());
}
if ($this->container->has(AppConfig::class)) {
$appConfig = $this->container->get(AppConfig::class);
$envType = $appConfig->environment;
} elseif ($this->container->has(TypedConfiguration::class)) {
$typedConfig = $this->container->get(TypedConfiguration::class);
$appConfigFromTyped = $typedConfig->appConfig();
$envType = is_string($appConfigFromTyped->environment)
? $appConfigFromTyped->environment
: $appConfigFromTyped->environment->value;
}
// Use factory methods which include default paths
return match ($envType) {
'development' => $factory->createForDevelopment(),
'testing' => $factory->createForTesting(),
default => $factory->createForProduction()
};
}
/**
* Führt einen inkrementellen Discovery-Scan durch
* Führt einen inkrementellen Discovery-Scan durch und verarbeitet die Ergebnisse
* mit context-aware Initializer-Verarbeitung
*/
public function incrementalBootstrap(): DiscoveryResults
public function incrementalBootstrap(): DiscoveryRegistry
{
if (!$this->container->has(UnifiedDiscoveryService::class)) {
if (! $this->container->has(UnifiedDiscoveryService::class)) {
// Fallback auf vollständigen Bootstrap
return $this->bootstrap();
}
@@ -147,7 +169,11 @@ final readonly class DiscoveryServiceBootstrapper
$results = $discoveryService->incrementalDiscover();
// Aktualisiere Container
$this->container->instance(DiscoveryResults::class, $results);
$this->container->instance(DiscoveryRegistry::class, $results);
// Re-process initializers for current context
$initializerProcessor = $this->container->get(InitializerProcessor::class);
$initializerProcessor->processInitializers($results);
return $results;
}
@@ -157,11 +183,12 @@ final readonly class DiscoveryServiceBootstrapper
*/
public function isDiscoveryRequired(): bool
{
if (!$this->container->has(UnifiedDiscoveryService::class)) {
if (! $this->container->has(UnifiedDiscoveryService::class)) {
return true;
}
$discoveryService = $this->container->get(UnifiedDiscoveryService::class);
return $discoveryService->shouldRescan();
}
}