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,43 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Application\Admin;
use App\Framework\Attributes\Route;
use App\Framework\Auth\Auth;
use App\Framework\Config\Environment;
use App\Framework\Config\TypedConfiguration;
use App\Framework\Core\VersionInfo;
use App\Framework\DateTime\Clock;
use App\Framework\DI\DefaultContainer;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Method;
use App\Framework\Http\Response;
use App\Framework\Meta\MetaData;
use App\Framework\Meta\OpenGraphTypeWebsite;
use App\Framework\Performance\MemoryUsageTracker;
use App\Framework\Router\Result\ViewResult;
use App\Framework\Http\Session\SessionManager;
use App\Framework\Http\Status;
use Dom\HTMLDocument;
use App\Framework\Meta\MetaData;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Redis\RedisConnectionPool;
use App\Framework\Router\Result\ViewResult;
final readonly class Dashboard
{
public function __construct(
private DefaultContainer $container,
private VersionInfo $versionInfo,
private MemoryUsageTracker $memoryTracker,
private TypedConfiguration $config,
) {}
private MemoryMonitor $memoryMonitor,
private Clock $clock,
) {
}
#[Auth]
#[Route(path: '/admin', method: Method::GET)]
public function show(): ViewResult
{
/** @var array<string, mixed> $stats */
$stats = [
'frameworkVersion' => $this->versionInfo->getVersion(),
'phpVersion' => PHP_VERSION,
'memoryUsage' => $this->formatBytes(memory_get_usage(true)),
'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
'memoryUsage' => $this->memoryMonitor->getCurrentMemory()->toHumanReadable(),
'peakMemoryUsage' => $this->memoryMonitor->getPeakMemory()->toHumanReadable(),
'serverInfo' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
'serverTime' => date('Y-m-d H:i:s'),
'serverTime' => $this->clock->now()->format('Y-m-d H:i:s'),
'timezone' => date_default_timezone_get(),
'operatingSystem' => PHP_OS,
'loadedExtensions' => $this->getLoadedExtensions(),
@@ -51,9 +57,10 @@ final readonly class Dashboard
return new ViewResult(
template: 'dashboard',
metaData: new MetaData('Admin Dashboard'),
/** @var array<string, mixed> */
data: [
'title' => 'Admin Dashboard',
'stats' => $stats
'stats' => $stats,
]
);
}
@@ -66,7 +73,7 @@ final readonly class Dashboard
$routes = $routeRegistry->getRoutes();
// Sort routes by path for better readability
usort($routes, function($a, $b) {
usort($routes, function ($a, $b) {
return strcmp($a->path, $b->path);
});
@@ -75,7 +82,7 @@ final readonly class Dashboard
metaData: new MetaData('', ''),
data: [
'title' => 'Routen-Übersicht',
'routes' => $routes
'routes' => $routes,
]
);
}
@@ -84,14 +91,44 @@ final readonly class Dashboard
#[Route(path: '/admin/services', method: Method::GET)]
public function services(): ViewResult
{
$services = $this->container->getServiceIds();
sort($services);
$registeredServices = $this->container->getRegisteredServices();
// The registered services are returned as a numeric array with class names as values
$serviceNames = array_filter($registeredServices, 'is_string');
$serviceNames = array_unique($serviceNames); // Remove duplicates
sort($serviceNames);
// Prepare service data with categorization
$serviceData = [];
foreach ($serviceNames as $serviceName) {
// Ensure $serviceName is a string before exploding
if (is_string($serviceName) && strpos($serviceName, '\\') !== false) {
$parts = explode('\\', $serviceName);
$category = $parts[1] ?? 'Unknown';
$subCategory = $parts[2] ?? '';
$serviceData[] = [
'name' => $serviceName,
'category' => $category,
'subCategory' => $subCategory,
];
} else {
// Handle non-namespaced services
$serviceData[] = [
'name' => (string)$serviceName,
'category' => 'Other',
'subCategory' => '',
];
}
}
return new ViewResult(
template: 'admin/services',
template: 'services',
metaData: new MetaData('', ''),
data: [
'title' => 'Registrierte Dienste',
'services' => $services
'services' => $serviceData,
'servicesCount' => count($serviceData),
]
);
}
@@ -100,27 +137,32 @@ final readonly class Dashboard
#[Route(path: '/admin/environment', method: Method::GET)]
public function environment(): ViewResult
{
$environment = $this->container->get(Environment::class);
/** @var array<int, array<string, string>> $env */
$env = [];
foreach ($_ENV as $key => $value) {
foreach ($environment->all() as $key => $value) {
// Maskiere sensible Daten
if (str_contains(strtolower($key), 'password') ||
str_contains(strtolower($key), 'secret') ||
str_contains(strtolower($key), 'key')) {
$value = '********';
}
$env[$key] = $value;
$env[] = [
'key' => $key,
'value' => is_array($value) ? json_encode($value) : (string)$value,
];
}
ksort($env);
dd($env);
// Sort by key
usort($env, fn ($a, $b) => strcmp($a['key'], $b['key']));
return new ViewResult(
template: 'admin/environment',
template: 'environment',
metaData: new MetaData('', ''),
data: [
'title' => 'Umgebungsvariablen',
'env' => $env
'env' => $env,
'current_year' => $this->clock->now()->format('Y'),
]
);
}
@@ -128,10 +170,10 @@ final readonly class Dashboard
#[Auth]
#[Route('/admin/phpinfo')]
#[Route(path: '/admin/phpinfo/{mode}', method: Method::GET)]
public function phpInfo(int $mode = 1): Response
public function phpInfo(string $mode = '1'): Response
{
ob_start();
phpinfo($mode);
phpinfo((int)$mode);
$phpinfo = ob_get_clean();
// Extraktion des <body> Inhalts, um nur den relevanten Teil anzuzeigen
@@ -182,15 +224,17 @@ final readonly class Dashboard
#[Route(path: '/admin/performance', method: Method::GET)]
public function performance(): ViewResult
{
/** @var array<string, mixed> $performanceData */
$performanceData = [
'currentMemoryUsage' => $this->formatBytes(memory_get_usage(true)),
'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
'memoryLimit' => $this->formatBytes($this->getMemoryLimitInBytes()),
'memoryUsagePercentage' => round((memory_get_usage(true) / $this->getMemoryLimitInBytes()) * 100, 2),
'currentMemoryUsage' => $this->memoryMonitor->getCurrentMemory()->toHumanReadable(),
'peakMemoryUsage' => $this->memoryMonitor->getPeakMemory()->toHumanReadable(),
'memoryLimit' => $this->memoryMonitor->getMemoryLimit()->toHumanReadable(),
'memoryUsagePercentage' => $this->memoryMonitor->getMemoryUsagePercentage()->format(2),
'loadAverage' => function_exists('sys_getloadavg') ? sys_getloadavg() : ['N/A', 'N/A', 'N/A'],
'opcacheEnabled' => function_exists('opcache_get_status') ? 'Ja' : 'Nein',
'executionTime' => number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 4) . ' Sekunden',
'includedFiles' => count(get_included_files()),
'files' => get_included_files(),
];
if (function_exists('opcache_get_status')) {
@@ -210,9 +254,11 @@ final readonly class Dashboard
return new ViewResult(
template: 'performance',
metaData: new MetaData('Performance-Daten', 'Performance-Daten'),
data: [
'title' => 'Performance-Daten',
'performance' => $performanceData
'performance' => $performanceData,
'current_year' => $this->clock->now()->format('Y'),
]
);
}
@@ -221,10 +267,11 @@ final readonly class Dashboard
#[Route(path: '/admin/redis', method: Method::GET)]
public function redisInfo(): ViewResult
{
/** @var array<string, mixed> $redisInfo */
$redisInfo = [];
try {
$redis = $this->container->get('Predis\Client');
$redis = $this->container->get(RedisConnectionPool::class)->getConnection()->getClient();
$info = $redis->info();
$redisInfo['status'] = 'Verbunden';
$redisInfo['version'] = $info['redis_version'];
@@ -236,16 +283,20 @@ final readonly class Dashboard
// Einige Schlüssel auflisten (begrenzt auf 50)
$keys = $redis->keys('*');
$redisInfo['key_sample'] = array_slice($keys, 0, 50);
/** @var array<int, string> $keySample */
$keySample = array_slice($keys, 0, 50);
$redisInfo['key_sample'] = $keySample;
} catch (\Throwable $e) {
$redisInfo['status'] = 'Fehler: ' . $e->getMessage();
}
return new ViewResult(
template: 'admin/redis',
template: 'redis',
metaData: new MetaData('Redis Information', 'Redis Information'),
data: [
'title' => 'Redis Information',
'redis' => $redisInfo
'redis' => $redisInfo,
'current_year' => $this->clock->now()->format('Y'),
]
);
}
@@ -272,25 +323,32 @@ final readonly class Dashboard
}
$value = (int) $memoryLimit;
$unit = strtolower($memoryLimit[strlen($memoryLimit)-1]);
$unit = strtolower($memoryLimit[strlen($memoryLimit) - 1]);
switch($unit) {
switch ($unit) {
case 'g':
$value *= 1024;
// no break
case 'm':
$value *= 1024;
// no break
case 'k':
$value *= 1024;
break;
}
return $value;
}
/**
* @return array<int, string>
*/
private function getLoadedExtensions(): array
{
$extensions = get_loaded_extensions();
sort($extensions);
return $extensions;
}
@@ -299,6 +357,7 @@ final readonly class Dashboard
try {
if ($this->container->has(SessionManager::class)) {
$sessionManager = $this->container->get(SessionManager::class);
// Diese Methode müsste implementiert werden
return $sessionManager->getActiveSessionCount();
}