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

@@ -4,84 +4,286 @@ declare(strict_types=1);
namespace App\Framework\Http;
use App\Framework\Core\InterfaceImplementationLocator;
use App\Framework\Cache\Cache;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\DI\Container;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Http\HttpMiddleware;
use App\Framework\Http\Middlewares\ControllerRequestMiddleware;
use App\Framework\Http\Middlewares\RoutingMiddleware;
use App\Framework\Validation\ValidationErrorMiddleware;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Http\Middlewares\DDoSProtectionMiddleware;
use App\Framework\Http\Middlewares\RateLimitMiddleware;
use App\Framework\Http\Middlewares\WafMiddleware;
use App\Framework\Logging\Logger;
use App\Framework\Reflection\ReflectionProvider;
/**
* Verwaltet die HTTP-Middleware-Pipeline
*/
final readonly class MiddlewareManager
final readonly class MiddlewareManager implements MiddlewareManagerInterface
{
/**
* @var array<string> Array mit Middleware-Klassen
*/
#private array $middlewares = [];
public HttpMiddlewareChain $chain;
public function __construct(
private Container $container,
private DiscoveryResults $discoveryResults,
)
{
// Standard-Middlewares registrieren
/*$this->middlewares = [
ControllerRequestMiddleware::class,
ValidationErrorMiddleware::class,
RoutingMiddleware::class
];*/
private DiscoveryRegistry $discoveryRegistry,
private ReflectionProvider $reflectionProvider,
private Cache $cache,
) {
$middlewares = $this->buildMiddlewareStack();
foreach($middlewares as $middleware) {
#echo $middleware . " " . $this->getMiddlewarePriority($middleware) . "<br>". PHP_EOL;
}
error_log("MiddlewareManager: Middleware stack: " . implode(', ', array_map(fn ($m) => basename($m), $middlewares)));
$this->chain = new HttpMiddlewareChain(
$middlewares,
fn() => new HttpResponse(Status::NOT_FOUND),
$this->container
);
}
private function buildMiddlewareStack(): array
{
$middlewares = $this->discoveryResults->get(HttpMiddleware::class);
$middlewares = array_column($middlewares, 'class');
return $this->sortMiddlewaresByPriority($middlewares);
// Explizite Reihenfolge definieren - wichtigste zuerst
$explicitOrder = [
// 0. Exception Handling - MUSS absolut zuerst kommen, um alle Exceptions zu fangen
\App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
// 1. System und Error Handling
\App\Framework\Http\Middlewares\RequestIdMiddleware::class,
// 2. Security und DDoS Protection
DDoSProtectionMiddleware::class,
WafMiddleware::class,
// 3. Session - MUSS vor Auth und CSRF kommen!
\App\Framework\Http\Session\SessionMiddleware::class,
// 4. Security und Rate Limiting
RateLimitMiddleware::class,
#\App\Application\Security\Middleware\SecurityEventMiddleware::class,
// 5. Headers und CORS
\App\Framework\Http\Middlewares\SecurityHeaderMiddleware::class,
\App\Framework\Http\Middlewares\RemovePoweredByMiddleware::class,
\App\Framework\Http\Middlewares\CORSMiddleware::class,
// 6. Authentication und CSRF (brauchen Session)
\App\Framework\Http\Middlewares\AuthMiddleware::class,
\App\Framework\Http\Middlewares\CsrfMiddleware::class,
\App\Framework\Http\Middlewares\HoneypotMiddleware::class,
// 7. Routing und Request Processing
\App\Framework\Http\Middlewares\RoutingMiddleware::class,
\App\Framework\Http\Middlewares\ControllerRequestMiddleware::class,
// 8. Content und Static Files
#\App\Framework\Http\Middlewares\ServeStaticFilesMiddleware::class,
\App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class,
\App\Framework\Http\Middlewares\FormDataResponseMiddleware::class, // Temporarily disabled
// 9. Monitoring und Analytics
\App\Framework\Analytics\Middleware\AnalyticsMiddleware::class,
\App\Framework\Performance\Middleware\RequestPerformanceMiddleware::class,
\App\Framework\Performance\Middleware\RoutingPerformanceMiddleware::class,
\App\Framework\Performance\Middleware\ControllerPerformanceMiddleware::class,
\App\Framework\Tracing\TracingMiddleware::class,
// 10. Logging (am Ende)
\App\Framework\Http\Middlewares\RequestLoggingMiddleware::class,
\App\Framework\Http\Middlewares\LoggingMiddleware::class,
\App\Framework\Performance\Middleware\PerformanceDebugMiddleware::class,
\App\Framework\Security\RequestSigning\RequestSigningMiddleware::class,
// 11. FALLBACK - Absolut letztes Middleware (nur wenn keine Response vorhanden)
\App\Framework\Http\Middlewares\DefaultResponseMiddleware::class,
];
// Use the refactored robust dependency resolution
try {
$resolved = $this->resolveDependencies($explicitOrder);
#error_log("MiddlewareManager: Using dependency resolution - Count: " . count($resolved));
// WICHTIG: Array umkehren, da die Liste in gewünschter Ausführungsreihenfolge definiert ist
// aber die Middleware-Chain sie in der gegebenen Reihenfolge abarbeitet
return array_reverse($resolved);
} catch (\Throwable $e) {
#error_log("MiddlewareManager: Dependency resolution failed: " . $e->getMessage());
#error_log("MiddlewareManager: Falling back to explicit order - Count: " . count($explicitOrder));
#foreach ($explicitOrder as $i => $middleware) {
# error_log("MiddlewareManager: Explicit #{$i}: " . basename($middleware));
#}
// WICHTIG: Array umkehren, da die Liste in gewünschter Ausführungsreihenfolge definiert ist
return array_reverse($explicitOrder);
}
}
/**
* Erstellt eine Middleware-Chain mit den registrierten Middlewares
* Resolve middleware dependencies using constructor analysis
* @param array<string> $middlewares
* @return array<string>
*/
/*public function createMiddlewareChain(callable $fallbackHandler): HttpMiddlewareChain
private function resolveDependencies(array $middlewares): array
{
return new HttpMiddlewareChain(
$this->middlewares,
$fallbackHandler,
$this->container
$logger = $this->container->get(Logger::class);
$resolver = new MiddlewareDependencyResolver(
$this->reflectionProvider,
$this->container,
$logger
);
}*/
$resolved = $resolver->resolve($middlewares);
// Log dependency resolution info
#error_log("MiddlewareManager: Dependency resolution completed");
#error_log("MiddlewareManager: Resolved " . $resolved->count() . " middlewares");
#error_log("MiddlewareManager: Execution order: " . implode(' → ', array_map(fn ($m) => basename($m), $resolved->getMiddlewares())));
// Log dependency chains for debugging
$info = $resolved->getResolutionInfo();
#if (! empty($info['dependency_chains'])) {
# error_log("MiddlewareManager: Dependency chains: " . json_encode($info['dependency_chains']));
#}
#if (! empty($info['circular_dependencies'])) {
# error_log("MiddlewareManager: WARNING - Circular dependencies detected: " . json_encode($info['circular_dependencies']));
#}
return $resolved->getMiddlewares();
}
/**
* Get middleware dependency information for debugging
*/
/**
* @return array<string, mixed>
*/
public function getDependencyInfo(): array
{
$explicitOrder = $this->getExplicitOrder();
$classNameObjects = array_map(fn ($class) => ClassName::create($class), $explicitOrder);
$logger = $this->container->get(Logger::class);
$resolver = new MiddlewareDependencyResolver(
$this->reflectionProvider,
$this->container,
$logger
);
return $resolver->getDependencyInfo($classNameObjects);
}
/**
* Get the explicit order array (for testing and debugging)
* @return array<string>
*/
private function getExplicitOrder(): array
{
// Return the same explicit order array
return [
// 1. System und Error Handling
\App\Framework\Http\Middlewares\RequestIdMiddleware::class,
\App\Framework\Http\Middlewares\ExceptionHandlingMiddleware::class,
// 4. Session - MUSS vor Auth und CSRF kommen!
\App\Framework\Http\Session\SessionMiddleware::class,
// 2. Security und Rate Limiting
RateLimitMiddleware::class,
#\App\Application\Security\Middleware\SecurityEventMiddleware::class,
// 3. Headers und CORS
\App\Framework\Http\Middlewares\SecurityHeaderMiddleware::class,
\App\Framework\Http\Middlewares\RemovePoweredByMiddleware::class,
\App\Framework\Http\Middlewares\CORSMiddleware::class,
// 5. Authentication und CSRF (brauchen Session)
\App\Framework\Http\Middlewares\AuthMiddleware::class,
\App\Framework\Http\Middlewares\CsrfMiddleware::class,
\App\Framework\Http\Middlewares\HoneypotMiddleware::class,
// 6. Routing und Request Processing
\App\Framework\Http\Middlewares\RoutingMiddleware::class,
\App\Framework\Http\Middlewares\ControllerRequestMiddleware::class,
// 7. Content und Static Files
#\App\Framework\Http\Middlewares\ServeStaticFilesMiddleware::class,
\App\Framework\Http\Middlewares\ResponseGeneratorMiddleware::class,
\App\Framework\Http\Middlewares\FormDataResponseMiddleware::class, // Temporarily disabled
// 8. Monitoring und Analytics
\App\Framework\Analytics\Middleware\AnalyticsMiddleware::class,
\App\Framework\Performance\Middleware\RequestPerformanceMiddleware::class,
\App\Framework\Performance\Middleware\RoutingPerformanceMiddleware::class,
\App\Framework\Performance\Middleware\ControllerPerformanceMiddleware::class,
\App\Framework\Tracing\TracingMiddleware::class,
// 9. Logging (am Ende)
\App\Framework\Http\Middlewares\RequestLoggingMiddleware::class,
\App\Framework\Http\Middlewares\LoggingMiddleware::class,
\App\Framework\Performance\Middleware\PerformanceDebugMiddleware::class,
\App\Framework\Security\RequestSigning\RequestSigningMiddleware::class,
// 10. FALLBACK - Absolut letztes Middleware (nur wenn keine Response vorhanden)
\App\Framework\Http\Middlewares\DefaultResponseMiddleware::class,
];
}
public function getPriorityForClass(object|string $middlewareClass): int
{
$className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class;
$className = ltrim($className, '\\');
$cacheKey = "middleware_priority:{$className}";
$cacheItem = $this->cache->remember($cacheKey, function () use ($className) {
return $this->resolvePriorityFromReflection($className);
}, 3600);
return is_int($cacheItem->value) ? $cacheItem->value : MiddlewarePriority::BUSINESS_LOGIC->value;
}
private function resolvePriorityFromReflection(string $className): int
{
try {
$classNameObj = ClassName::create($className);
$attrs = $this->reflectionProvider->getAttributes($classNameObj, MiddlewarePriorityAttribute::class);
if ($attrs->count() > 0) {
/** @var MiddlewarePriorityAttribute|null $attr */
$attr = $attrs->getFirstByType(MiddlewarePriorityAttribute::class)?->newInstance();
if ($attr instanceof MiddlewarePriorityAttribute) {
$basePriority = $attr->priority->value;
$offset = $attr->offset ?? 0;
return $basePriority + $offset;
}
}
} catch (\ReflectionException $e) {
// Class doesn't exist or can't be reflected, use default
}
// Default priority
return MiddlewarePriority::BUSINESS_LOGIC->value;
}
// Legacy static method for backward compatibility
public static function getPriority(object|string $middlewareClass): int
{
$reflection = new \ReflectionClass($middlewareClass);
$attrs = $reflection->getAttributes(MiddlewarePriorityAttribute::class);
if ($attrs) {
/** @var MiddlewarePriorityAttribute $attr */
$attr = $attrs[0]->newInstance();
if ($attr->offset !== 0) {
return $attr->priority->value + $attr->offset;
// This is a fallback for any code that still uses the static method
$className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class;
$className = ltrim($className, '\\');
try {
$reflection = new \ReflectionClass($className);
$attrs = $reflection->getAttributes(MiddlewarePriorityAttribute::class);
if ($attrs) {
/** @var MiddlewarePriorityAttribute $attr */
$attr = $attrs[0]->newInstance();
$basePriority = $attr->priority->value;
$offset = $attr->offset ?? 0;
return $basePriority + $offset;
}
return $attr->priority->value;
} catch (\ReflectionException $e) {
// Class doesn't exist or can't be reflected, use default
}
// Standard-Priorität (oder Fehlermeldung)
return MiddlewarePriority::BUSINESS_LOGIC->value;
}
@@ -101,24 +303,52 @@ final readonly class MiddlewareManager
// Hilfsmethode zum Abrufen der Middleware-Priorität
private function getMiddlewarePriority(object|string $middlewareClass): int
{
$priority = $this->discoveryResults->get(MiddlewarePriorityAttribute::class);
$middlewareClass = ltrim($middlewareClass, '\\');
$className = is_string($middlewareClass) ? $middlewareClass : $middlewareClass::class;
$className = ltrim($className, '\\');
foreach($priority as $item) {
#dd($middlewareClass);
if ($item['class'] === $middlewareClass) {
#debug($item['attribute_data']['priority']);
#dd($item['attribute_data']['priority']->value);
$priority = $item['attribute_data']['priority'];
if(!is_int($priority)) {
$priority = $priority->value;
$cacheKey = "middleware_priority_discovery:{$className}";
$cacheItem = $this->cache->remember($cacheKey, function () use ($className) {
// Use discovery registry to find priority
$priorities = $this->discoveryRegistry->attributes()->get(MiddlewarePriorityAttribute::class);
foreach ($priorities as $discoveredAttribute) {
if ($discoveredAttribute->className->getFullyQualified() === $className) {
$additionalData = $discoveredAttribute->additionalData;
$priority = $additionalData['priority'] ?? null;
if (! is_int($priority)) {
$priority = $priority->value;
}
return $priority + ($additionalData['offset'] ?? 0);
}
return $priority + ($item['attribute_data']['offset'] ?? 0);
}
}
// Middleware has no Priority: Set to default
return MiddlewarePriority::BUSINESS_LOGIC->value;
// Default priority
return MiddlewarePriority::BUSINESS_LOGIC->value;
}, 3600);
return is_int($cacheItem->value) ? $cacheItem->value : MiddlewarePriority::BUSINESS_LOGIC->value;
}
/**
* Clear the priority cache (useful for testing)
*/
public function clearPriorityCache(): void
{
// Clear cache entries that start with our middleware priority prefix
$this->cache->forget('middleware_priority:*');
$this->cache->forget('middleware_priority_discovery:*');
}
/**
* Get cache statistics for debugging
*/
public function getCacheStats(): array
{
return [
'cache_implementation' => get_class($this->cache),
'reflection_provider' => get_class($this->reflectionProvider),
];
}
}