hasOption('detailed'); $fixPermissions = $input->hasOption('fix-permissions'); $basePath = getcwd() ?: '/var/www/html'; $logsPath = $basePath . '/storage/logs'; echo "═══════════════════════════════════════════════════\n"; echo " Log Infrastructure Health Check \n"; echo "═══════════════════════════════════════════════════\n\n"; $checks = [ 'directories' => $this->checkDirectories($logsPath, $basePath, $fixPermissions), 'permissions' => $this->checkPermissions($logsPath, $basePath, $fixPermissions), 'disk_space' => $this->checkDiskSpace($logsPath, $basePath), 'log_files' => $this->checkLogFiles($logsPath, $basePath, $detailed), ]; // Summary echo "\n═══════════════════════════════════════════════════\n"; echo " Summary \n"; echo "═══════════════════════════════════════════════════\n"; $allPassed = true; foreach ($checks as $checkName => $passed) { $status = $passed ? '✓ PASS' : '✗ FAIL'; $color = $passed ? "\033[32m" : "\033[31m"; echo $color . $status . "\033[0m " . str_pad(ucfirst(str_replace('_', ' ', $checkName)), 30) . "\n"; if (!$passed) { $allPassed = false; } } echo "\n"; if ($allPassed) { echo "\033[32m✓ All checks passed! Log infrastructure is healthy.\033[0m\n"; return ExitCode::SUCCESS; } echo "\033[31m✗ Some checks failed. Please review above output.\033[0m\n"; if (!$fixPermissions) { echo "\033[33mTip: Use --fix-permissions to automatically fix permission issues.\033[0m\n"; } return ExitCode::GENERAL_ERROR; } /** * Prüft ob Log-Verzeichnisse existieren */ private function checkDirectories(string $logsPath, string $basePath, bool $fix): bool { echo "📁 Checking log directories...\n"; $directories = [ $logsPath, $logsPath . '/app', $logsPath . '/debug', $logsPath . '/security', ]; $allExist = true; foreach ($directories as $dir) { $exists = is_dir($dir); if ($exists) { echo " ✓ " . $this->relativePath($dir, $basePath) . "\n"; } else { echo " ✗ " . $this->relativePath($dir, $basePath) . " (missing)\n"; $allExist = false; if ($fix) { echo " → Creating directory...\n"; mkdir($dir, 0777, true); echo " ✓ Directory created\n"; $allExist = true; } } } echo "\n"; return $allExist; } /** * Prüft Schreibberechtigungen */ private function checkPermissions(string $logsPath, string $basePath, bool $fix): bool { echo "🔐 Checking write permissions...\n"; $testFile = $logsPath . '/.health-check-' . uniqid() . '.tmp'; try { // Versuche Test-Datei zu schreiben $result = @file_put_contents($testFile, 'health check test'); if ($result === false) { echo " ✗ Cannot write to " . $this->relativePath($logsPath, $basePath) . "\n"; if ($fix) { echo " → Attempting to fix permissions...\n"; @chmod($logsPath, 0777); @chmod(dirname($logsPath), 0777); // Retry $result = @file_put_contents($testFile, 'health check test'); if ($result !== false) { echo " ✓ Permissions fixed\n"; @unlink($testFile); echo "\n"; return true; } } echo "\n"; return false; } // Cleanup @unlink($testFile); $perms = substr(sprintf('%o', fileperms($logsPath)), -4); echo " ✓ Write permissions OK (permissions: " . $perms . ")\n"; echo "\n"; return true; } catch (\Throwable $e) { echo " ✗ Permission check failed: " . $e->getMessage() . "\n"; echo "\n"; return false; } } /** * Prüft verfügbaren Disk-Space */ private function checkDiskSpace(string $logsPath, string $basePath): bool { echo "💾 Checking disk space...\n"; $freeSpace = disk_free_space($logsPath); $totalSpace = disk_total_space($logsPath); if ($freeSpace === false || $totalSpace === false) { echo " ✗ Could not determine disk space\n"; echo "\n"; return false; } $freeBytes = Byte::fromBytes((int) $freeSpace); $totalBytes = Byte::fromBytes((int) $totalSpace); $usedBytes = Byte::fromBytes((int) ($totalSpace - $freeSpace)); $percentUsed = ($totalSpace > 0) ? round(($totalSpace - $freeSpace) / $totalSpace * 100, 2) : 0; echo " Total: " . $totalBytes->toHumanReadable() . "\n"; echo " Used: " . $usedBytes->toHumanReadable() . " (" . $percentUsed . "%)\n"; echo " Free: " . $freeBytes->toHumanReadable() . "\n"; // Warn if less than 100MB free or more than 90% used if ($freeSpace < 100 * 1024 * 1024 || $percentUsed > 90) { echo " \033[33m⚠ Warning: Low disk space!\033[0m\n"; echo "\n"; return false; } echo " ✓ Disk space OK\n"; echo "\n"; return true; } /** * Prüft Log-Dateien */ private function checkLogFiles(string $logsPath, string $basePath, bool $detailed): bool { echo "📄 Checking log files...\n"; $logFiles = $this->findLogFiles($logsPath); if (empty($logFiles)) { echo " ℹ No log files found (this is OK for a fresh install)\n"; echo "\n"; return true; } echo " Found " . count($logFiles) . " log file(s)\n\n"; $totalSize = 0; $warnings = []; foreach ($logFiles as $logFile) { $size = filesize($logFile); $totalSize += $size; $sizeBytes = Byte::fromBytes($size); $modified = date('Y-m-d H:i:s', filemtime($logFile)); if ($detailed) { echo " " . $this->relativePath($logFile, $basePath) . "\n"; echo " Size: " . $sizeBytes->toHumanReadable() . "\n"; echo " Modified: " . $modified . "\n"; // Check if file is very large if ($size > 50 * 1024 * 1024) { // 50MB echo " \033[33m⚠ Large file (consider rotation)\033[0m\n"; $warnings[] = $logFile; } echo "\n"; } } $totalBytes = Byte::fromBytes($totalSize); echo " Total log size: " . $totalBytes->toHumanReadable() . "\n"; if (!empty($warnings)) { echo "\n \033[33m⚠ " . count($warnings) . " file(s) exceed 50MB\033[0m\n"; } echo "\n"; return empty($warnings); } /** * Findet alle Log-Dateien rekursiv */ private function findLogFiles(string $directory): array { $files = []; $iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $file) { if ($file->isFile() && preg_match('/\.(log|log\.\d+|log\.\d+\.gz)$/', $file->getFilename())) { $files[] = $file->getPathname(); } } return $files; } /** * Gibt relativen Pfad zurück */ private function relativePath(string $path, string $basePath): string { return str_replace($basePath . '/', '', $path); } }