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 | } |