Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 63 |
|
0.00% |
0 / 14 |
CRAP | |
0.00% |
0 / 1 |
| MonitorLogsCommand | |
0.00% |
0 / 63 |
|
0.00% |
0 / 14 |
1722 | |
0.00% |
0 / 1 |
| getAllowedAppEnvs | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| handle | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
110 | |||
| checkEmergencies | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| checkAlerts | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| checkCritical | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| checkManyErrors | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| checkManyWarnings | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| checkManyNotices | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| isEmergencyLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| isAlertLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| isCriticalLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| isErrorLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| isWarningLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| isNoticeLine | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace Olz\Command; |
| 4 | |
| 5 | use Olz\Command\Common\OlzCommand; |
| 6 | use Symfony\Component\Console\Attribute\AsCommand; |
| 7 | use Symfony\Component\Console\Command\Command; |
| 8 | use Symfony\Component\Console\Input\InputInterface; |
| 9 | use Symfony\Component\Console\Output\OutputInterface; |
| 10 | |
| 11 | #[AsCommand(name: 'olz:monitor-logs')] |
| 12 | class MonitorLogsCommand extends OlzCommand { |
| 13 | /** @return array<string> */ |
| 14 | protected function getAllowedAppEnvs(): array { |
| 15 | return ['dev', 'test', 'staging', 'prod']; |
| 16 | } |
| 17 | |
| 18 | protected function handle(InputInterface $input, OutputInterface $output): int { |
| 19 | $private_path = $this->envUtils()->getPrivatePath(); |
| 20 | $logs_path = "{$private_path}logs/"; |
| 21 | if (!is_dir($logs_path)) { |
| 22 | throw new \Exception("Expected {$logs_path} to be a directory"); |
| 23 | } |
| 24 | |
| 25 | $last_two_merged_log_file_contents = ""; |
| 26 | $merged_log_index = 0; |
| 27 | $filenames = scandir($logs_path, SCANDIR_SORT_DESCENDING) ?: []; |
| 28 | foreach ($filenames as $filename) { |
| 29 | if ($merged_log_index > 1) { |
| 30 | break; |
| 31 | } |
| 32 | if (preg_match('/^merged-.*\.log$/', $filename)) { |
| 33 | $last_two_merged_log_file_contents = file_get_contents("{$logs_path}{$filename}").$last_two_merged_log_file_contents; |
| 34 | $merged_log_index++; |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | $now = new \DateTime(); |
| 39 | $minus_one_hour = \DateInterval::createFromDateString("-1 hours"); |
| 40 | $one_hour_ago = $now->add($minus_one_hour); |
| 41 | |
| 42 | $logs_in_last_hour = []; |
| 43 | |
| 44 | foreach (explode("\n", $last_two_merged_log_file_contents) as $line) { |
| 45 | $res = preg_match('/^\[([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2})/', $line, $matches); |
| 46 | if ($res) { |
| 47 | $line_timestamp = strtotime($matches[1]) ?: 0; |
| 48 | if ($line_timestamp > $one_hour_ago->getTimestamp()) { |
| 49 | $logs_in_last_hour[] = $line; |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | $output->writeln("Last hour: ".count($logs_in_last_hour)." logs"); |
| 55 | |
| 56 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isEmergencyLine($line); }))." emergency logs"); |
| 57 | |
| 58 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isAlertLine($line); }))." alert logs"); |
| 59 | |
| 60 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isCriticalLine($line); }))." critical logs"); |
| 61 | |
| 62 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isErrorLine($line); }))." error logs"); |
| 63 | |
| 64 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isWarningLine($line); }))." warning logs"); |
| 65 | |
| 66 | $output->writeln("Last hour: ".count(array_filter($logs_in_last_hour, function ($line) { return $this->isNoticeLine($line); }))." notice logs"); |
| 67 | |
| 68 | $this->checkEmergencies($logs_in_last_hour); |
| 69 | $this->checkAlerts($logs_in_last_hour); |
| 70 | $this->checkCritical($logs_in_last_hour); |
| 71 | $this->checkManyErrors($logs_in_last_hour); |
| 72 | $this->checkManyWarnings($logs_in_last_hour); |
| 73 | $this->checkManyNotices($logs_in_last_hour); |
| 74 | |
| 75 | $output->writeln("OK:"); |
| 76 | return Command::SUCCESS; |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | * @param array<string> $logs_in_last_hour |
| 81 | */ |
| 82 | protected function checkEmergencies(array $logs_in_last_hour): void { |
| 83 | if (count(array_filter($logs_in_last_hour, function ($line) { return $this->isEmergencyLine($line); })) > 0) { |
| 84 | throw new \Exception("Expected no emergencies"); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * @param array<string> $logs_in_last_hour |
| 90 | */ |
| 91 | protected function checkAlerts(array $logs_in_last_hour): void { |
| 92 | if (count(array_filter($logs_in_last_hour, function ($line) { return $this->isAlertLine($line); })) > 0) { |
| 93 | throw new \Exception("Expected no alerts"); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * @param array<string> $logs_in_last_hour |
| 99 | */ |
| 100 | protected function checkCritical(array $logs_in_last_hour): void { |
| 101 | if (count(array_filter($logs_in_last_hour, function ($line) { return $this->isCriticalLine($line); })) > 0) { |
| 102 | throw new \Exception("Expected no critical log entries"); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * @param array<string> $logs_in_last_hour |
| 108 | */ |
| 109 | protected function checkManyErrors(array $logs_in_last_hour): void { |
| 110 | $limit_per_hour = 1; |
| 111 | |
| 112 | $errors_per_hour = count(array_filter($logs_in_last_hour, function ($line) { return $this->isErrorLine($line); })); |
| 113 | if ($errors_per_hour > $limit_per_hour) { |
| 114 | throw new \Exception("Expected fewer error log entries per hour ({$errors_per_hour} > {$limit_per_hour})"); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | /** |
| 119 | * @param array<string> $logs_in_last_hour |
| 120 | */ |
| 121 | protected function checkManyWarnings(array $logs_in_last_hour): void { |
| 122 | $limit_per_hour = 10; |
| 123 | |
| 124 | $warnings_per_hour = count(array_filter($logs_in_last_hour, function ($line) { return $this->isWarningLine($line); })); |
| 125 | if ($warnings_per_hour > $limit_per_hour) { |
| 126 | throw new \Exception("Expected fewer warning log entries per hour ({$warnings_per_hour} > {$limit_per_hour})"); |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | /** |
| 131 | * @param array<string> $logs_in_last_hour |
| 132 | */ |
| 133 | protected function checkManyNotices(array $logs_in_last_hour): void { |
| 134 | $limit_per_hour = 100; |
| 135 | |
| 136 | $notices_per_hour = count(array_filter($logs_in_last_hour, function ($line) { return $this->isNoticeLine($line); })); |
| 137 | if ($notices_per_hour > $limit_per_hour) { |
| 138 | throw new \Exception("Expected fewer notice log entries per hour ({$notices_per_hour} > {$limit_per_hour})"); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | protected function isEmergencyLine(string $line): bool { |
| 143 | return preg_match('/\.EMERGENCY\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.EMERGENCY\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 144 | } |
| 145 | |
| 146 | protected function isAlertLine(string $line): bool { |
| 147 | return preg_match('/\.ALERT\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.ALERT\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 148 | } |
| 149 | |
| 150 | protected function isCriticalLine(string $line): bool { |
| 151 | return preg_match('/\.CRITICAL\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.CRITICAL\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 152 | } |
| 153 | |
| 154 | protected function isErrorLine(string $line): bool { |
| 155 | return preg_match('/\.ERROR\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.ERROR\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 156 | } |
| 157 | |
| 158 | protected function isWarningLine(string $line): bool { |
| 159 | return preg_match('/\.WARNING\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.WARNING\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 160 | } |
| 161 | |
| 162 | protected function isNoticeLine(string $line): bool { |
| 163 | return preg_match('/\.NOTICE\:/', $line) && !preg_match('/Tool\:\w+-monitoring\.NOTICE\:/', $line) && !preg_match('/Olz\\\Command\\\Monitor/', $line); |
| 164 | } |
| 165 | } |