refactor(deployment): Remove WireGuard VPN dependency and restore public service access
Remove WireGuard integration from production deployment to simplify infrastructure: - Remove docker-compose-direct-access.yml (VPN-bound services) - Remove VPN-only middlewares from Grafana, Prometheus, Portainer - Remove WireGuard middleware definitions from Traefik - Remove WireGuard IPs (10.8.0.0/24) from Traefik forwarded headers All monitoring services now publicly accessible via subdomains: - grafana.michaelschiemer.de (with Grafana native auth) - prometheus.michaelschiemer.de (with Basic Auth) - portainer.michaelschiemer.de (with Portainer native auth) All services use Let's Encrypt SSL certificates via Traefik.
This commit is contained in:
291
src/Framework/Process/Console/LogCommands.php
Normal file
291
src/Framework/Process/Console/LogCommands.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Process\Console;
|
||||
|
||||
use App\Framework\Console\ConsoleCommand;
|
||||
use App\Framework\Console\ConsoleInput;
|
||||
use App\Framework\Console\ExitCode;
|
||||
use App\Framework\Filesystem\ValueObjects\FilePath;
|
||||
use App\Framework\Process\Services\LogAnalysisService;
|
||||
|
||||
/**
|
||||
* Log Console Commands.
|
||||
*/
|
||||
final readonly class LogCommands
|
||||
{
|
||||
public function __construct(
|
||||
private LogAnalysisService $logAnalysis
|
||||
) {
|
||||
}
|
||||
|
||||
#[ConsoleCommand('log:tail', 'Display last N lines of a log file')]
|
||||
public function tail(ConsoleInput $input): int
|
||||
{
|
||||
$filePath = $input->getArgument('file');
|
||||
|
||||
if ($filePath === null) {
|
||||
echo "❌ Please provide a log file path.\n";
|
||||
echo "Usage: php console.php log:tail <file> [--lines=100]\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$file = FilePath::create($filePath);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Invalid file path: {$filePath}\n";
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if (! $file->exists() || ! $file->isFile()) {
|
||||
echo "❌ File does not exist or is not a file: {$filePath}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
$lines = (int) ($input->getOption('lines') ?? 100);
|
||||
|
||||
echo "Showing last {$lines} lines of: {$file->toString()}\n\n";
|
||||
echo "--- LOG OUTPUT ---\n\n";
|
||||
|
||||
$output = $this->logAnalysis->tail($file, $lines);
|
||||
echo $output;
|
||||
|
||||
if (empty($output)) {
|
||||
echo "(No content)\n";
|
||||
}
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('log:errors', 'Find errors in a log file')]
|
||||
public function errors(ConsoleInput $input): int
|
||||
{
|
||||
$filePath = $input->getArgument('file');
|
||||
|
||||
if ($filePath === null) {
|
||||
echo "❌ Please provide a log file path.\n";
|
||||
echo "Usage: php console.php log:errors <file> [--lines=1000]\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$file = FilePath::create($filePath);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Invalid file path: {$filePath}\n";
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if (! $file->exists() || ! $file->isFile()) {
|
||||
echo "❌ File does not exist or is not a file: {$filePath}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
$lines = (int) ($input->getOption('lines') ?? 1000);
|
||||
|
||||
echo "Searching for errors in: {$file->toString()} (last {$lines} lines)...\n\n";
|
||||
|
||||
$result = $this->logAnalysis->findErrors($file, $lines);
|
||||
|
||||
if (empty($result->entries)) {
|
||||
echo "✅ No errors found!\n";
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
echo "┌─ ERRORS FOUND ──────────────────────────────────────────┐\n";
|
||||
echo "│ Total Errors: {$result->getErrorCount()}\n";
|
||||
echo "│ Total Lines: {$result->totalLines}\n";
|
||||
echo "└─────────────────────────────────────────────────────────┘\n\n";
|
||||
|
||||
echo "Error Entries:\n";
|
||||
foreach ($result->entries as $entry) {
|
||||
$timestamp = $entry->timestamp?->format('Y-m-d H:i:s') ?? 'N/A';
|
||||
echo " [{$timestamp}] {$entry->level}: {$entry->message}\n";
|
||||
}
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('log:warnings', 'Find warnings in a log file')]
|
||||
public function warnings(ConsoleInput $input): int
|
||||
{
|
||||
$filePath = $input->getArgument('file');
|
||||
|
||||
if ($filePath === null) {
|
||||
echo "❌ Please provide a log file path.\n";
|
||||
echo "Usage: php console.php log:warnings <file> [--lines=1000]\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$file = FilePath::create($filePath);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Invalid file path: {$filePath}\n";
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if (! $file->exists() || ! $file->isFile()) {
|
||||
echo "❌ File does not exist or is not a file: {$filePath}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
$lines = (int) ($input->getOption('lines') ?? 1000);
|
||||
|
||||
echo "Searching for warnings in: {$file->toString()} (last {$lines} lines)...\n\n";
|
||||
|
||||
$result = $this->logAnalysis->findWarnings($file, $lines);
|
||||
|
||||
if (empty($result->entries)) {
|
||||
echo "✅ No warnings found!\n";
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
echo "┌─ WARNINGS FOUND ────────────────────────────────────────┐\n";
|
||||
echo "│ Total Warnings: {$result->getWarningCount()}\n";
|
||||
echo "│ Total Lines: {$result->totalLines}\n";
|
||||
echo "└─────────────────────────────────────────────────────────┘\n\n";
|
||||
|
||||
echo "Warning Entries:\n";
|
||||
foreach ($result->entries as $entry) {
|
||||
$timestamp = $entry->timestamp?->format('Y-m-d H:i:s') ?? 'N/A';
|
||||
echo " [{$timestamp}] {$entry->level}: {$entry->message}\n";
|
||||
}
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('log:search', 'Search for a pattern in a log file')]
|
||||
public function search(ConsoleInput $input): int
|
||||
{
|
||||
$filePath = $input->getArgument('file');
|
||||
$pattern = $input->getArgument('pattern');
|
||||
|
||||
if ($filePath === null || $pattern === null) {
|
||||
echo "❌ Please provide a log file path and search pattern.\n";
|
||||
echo "Usage: php console.php log:search <file> <pattern> [--lines=1000]\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$file = FilePath::create($filePath);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Invalid file path: {$filePath}\n";
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if (! $file->exists() || ! $file->isFile()) {
|
||||
echo "❌ File does not exist or is not a file: {$filePath}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
$lines = (int) ($input->getOption('lines') ?? 1000);
|
||||
|
||||
echo "Searching for '{$pattern}' in: {$file->toString()} (last {$lines} lines)...\n\n";
|
||||
|
||||
$result = $this->logAnalysis->search($file, $pattern, $lines);
|
||||
|
||||
if (empty($result->entries)) {
|
||||
echo "ℹ️ No matches found for pattern: {$pattern}\n";
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
echo "┌─ SEARCH RESULTS ────────────────────────────────────────┐\n";
|
||||
echo "│ Pattern: {$pattern}\n";
|
||||
echo "│ Matches: " . count($result->entries) . "\n";
|
||||
echo "│ Total Lines: {$result->totalLines}\n";
|
||||
echo "└─────────────────────────────────────────────────────────┘\n\n";
|
||||
|
||||
echo "Matching Entries:\n";
|
||||
foreach ($result->entries as $entry) {
|
||||
$timestamp = $entry->timestamp?->format('Y-m-d H:i:s') ?? 'N/A';
|
||||
echo " [{$timestamp}] {$entry->level}: {$entry->message}\n";
|
||||
}
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
#[ConsoleCommand('log:stats', 'Show statistics for a log file')]
|
||||
public function stats(ConsoleInput $input): int
|
||||
{
|
||||
$filePath = $input->getArgument('file');
|
||||
|
||||
if ($filePath === null) {
|
||||
echo "❌ Please provide a log file path.\n";
|
||||
echo "Usage: php console.php log:stats <file> [--lines=1000]\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$file = FilePath::create($filePath);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo "❌ Invalid file path: {$filePath}\n";
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
if (! $file->exists() || ! $file->isFile()) {
|
||||
echo "❌ File does not exist or is not a file: {$filePath}\n";
|
||||
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
$lines = (int) ($input->getOption('lines') ?? 1000);
|
||||
|
||||
echo "Analyzing log file: {$file->toString()} (last {$lines} lines)...\n\n";
|
||||
|
||||
$stats = $this->logAnalysis->getStatistics($file, $lines);
|
||||
|
||||
echo "╔════════════════════════════════════════════════════════════╗\n";
|
||||
echo "║ LOG STATISTICS ║\n";
|
||||
echo "╚════════════════════════════════════════════════════════════╝\n\n";
|
||||
|
||||
echo "┌─ OVERVIEW ──────────────────────────────────────────────┐\n";
|
||||
echo "│ Total Lines: {$stats['total_lines']}\n";
|
||||
echo "│ Errors: {$stats['error_count']}\n";
|
||||
echo "│ Warnings: {$stats['warning_count']}\n";
|
||||
echo "└─────────────────────────────────────────────────────────┘\n\n";
|
||||
|
||||
if (! empty($stats['level_distribution'])) {
|
||||
echo "┌─ LEVEL DISTRIBUTION ───────────────────────────────────┐\n";
|
||||
foreach ($stats['level_distribution'] as $level => $count) {
|
||||
echo "│ {$level}: {$count}\n";
|
||||
}
|
||||
echo "└─────────────────────────────────────────────────────────┘\n\n";
|
||||
}
|
||||
|
||||
if (! empty($stats['top_errors'])) {
|
||||
echo "┌─ TOP ERRORS ──────────────────────────────────────────┐\n";
|
||||
$rank = 1;
|
||||
foreach ($stats['top_errors'] as $message => $count) {
|
||||
echo "│ {$rank}. ({$count}x) {$message}\n";
|
||||
$rank++;
|
||||
}
|
||||
echo "└─────────────────────────────────────────────────────────┘\n";
|
||||
}
|
||||
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user