diff --git a/src/Cli/Commands/WatchdogCommand.php b/src/Cli/Commands/WatchdogCommand.php index 3350c3a7..849baa86 100644 --- a/src/Cli/Commands/WatchdogCommand.php +++ b/src/Cli/Commands/WatchdogCommand.php @@ -100,9 +100,8 @@ class WatchdogCommand implements CommandInterface { // ── Nginx stats ────────────────────────────────────── // Each pass is a fresh process (restartDaemon re-execs), so the // previous request count is kept in a state file, not a variable. - $rNginx = explode("\n", (string) @file_get_contents('http://127.0.0.1:' . $rServers[SERVER_ID]['http_broadcast_port'] . '/nginx_status')); - $rRequests = explode(' ', trim($rNginx[2] ?? ''))[2] ?? null; - $rRequestsPerSecond = is_numeric($rRequests) ? (new CounterRateSampler(TMP_PATH . 'watchdog_nginx_requests.json'))->sample((float) $rRequests, time()) : 0; + $rRequests = SystemInfo::nginxRequestCount((string) @file_get_contents('http://127.0.0.1:' . $rServers[SERVER_ID]['http_broadcast_port'] . '/nginx_status')); + $rRequestsPerSecond = ($rRequests === null ? 0 : (new CounterRateSampler(TMP_PATH . 'watchdog_nginx_requests.json'))->sample($rRequests, time())); // ── CPU stats ──────────────────────────────────────── $rStats = SystemInfo::getStats(); diff --git a/src/Core/Util/SystemInfo.php b/src/Core/Util/SystemInfo.php index 9e08a3c3..091d316c 100644 --- a/src/Core/Util/SystemInfo.php +++ b/src/Core/Util/SystemInfo.php @@ -251,6 +251,20 @@ class SystemInfo { return $rReturn; } + /** + * Total request count from an nginx stub_status body. + * + * The third line holds the accepts, handled and requests counters + * (" 10 10 57 "); the request count is the third of them. + * + * @param string $rStatus stub_status response body ('' when unreachable) + * @return float|null The request count; null when the body has none + */ + public static function nginxRequestCount(string $rStatus) { + $rRequests = explode(' ', trim(explode("\n", $rStatus)[2] ?? ''))[2] ?? null; + return is_numeric($rRequests) ? (float) $rRequests : null; + } + /** * List V4L2 video capture devices. * diff --git a/tests/Unit/CounterRateSamplerTest.php b/tests/Unit/CounterRateSamplerTest.php index 3b1d8509..cfe1cc73 100644 --- a/tests/Unit/CounterRateSamplerTest.php +++ b/tests/Unit/CounterRateSamplerTest.php @@ -67,6 +67,7 @@ final class CounterRateSamplerTest extends TestCase { $rSampler = new CounterRateSampler($this->rFile); $rSampler->sample(1000, 100); $this->assertSame(0, $rSampler->sample(2210, 221)); + $this->assertSame(10, $rSampler->sample(3410, 341), '120 s is in range by default'); } public function testACorruptStateFileIsZeroAndOverwritten(): void { @@ -92,6 +93,7 @@ final class CounterRateSamplerTest extends TestCase { $this->assertFileExists($rPath); $rSource = (string) file_get_contents($rPath); + $this->assertStringContainsString('SystemInfo::nginxRequestCount(', $rSource); $this->assertStringContainsString('new CounterRateSampler(TMP_PATH . ', $rSource); $this->assertStringNotContainsString('$rLastRequests', $rSource, 'a per-process previous reading is always null'); } diff --git a/tests/Unit/SystemInfoNetworkTest.php b/tests/Unit/SystemInfoNetworkTest.php index ecc85f93..5d32a1f4 100644 --- a/tests/Unit/SystemInfoNetworkTest.php +++ b/tests/Unit/SystemInfoNetworkTest.php @@ -93,7 +93,8 @@ final class SystemInfoNetworkTest extends TestCase { public function testGetStatsTakesItsBandwidthFromAggregateNetwork(): void { $rSource = (string) file_get_contents(MAIN_HOME . 'Core/Util/SystemInfo.php'); - $this->assertStringContainsString('self::aggregateNetwork($rJSON[\'network_info\'])', $rSource); + // array_replace, not `+`: the keys already exist (as 0) and must be overwritten in place. + $this->assertStringContainsString("\$rJSON = array_replace(\$rJSON, self::aggregateNetwork(\$rJSON['network_info']));", $rSource); $this->assertStringNotContainsString("\$rJSON['bytes_sent_total'] = (", $rSource, 'the total must not be assigned per interface'); } } diff --git a/tests/Unit/SystemInfoNginxStatusTest.php b/tests/Unit/SystemInfoNginxStatusTest.php new file mode 100644 index 00000000..bb680c93 --- /dev/null +++ b/tests/Unit/SystemInfoNginxStatusTest.php @@ -0,0 +1,27 @@ +assertSame(57.0, SystemInfo::nginxRequestCount($rStatus)); + } + + public function testAnUnreachableOrMalformedStatusHasNoCount(): void { + // The watchdog passes '' when the status page cannot be fetched. + $this->assertNull(SystemInfo::nginxRequestCount('')); + $this->assertNull(SystemInfo::nginxRequestCount("Active connections: 3 \nserver accepts handled requests\n")); + $this->assertNull(SystemInfo::nginxRequestCount("Active connections: 3 \nserver accepts handled requests\n 10 10 \n")); + $this->assertNull(SystemInfo::nginxRequestCount("\n