diff --git a/src/dstack/_internal/proxy/gateway/services/stats.py b/src/dstack/_internal/proxy/gateway/services/stats.py index 358eff451..f29707b7e 100644 --- a/src/dstack/_internal/proxy/gateway/services/stats.py +++ b/src/dstack/_internal/proxy/gateway/services/stats.py @@ -121,10 +121,14 @@ def _read_access_log(self, after: datetime.datetime) -> Iterable[LogEntry]: line = self._file.readline() if not line: break - cells = line.split() + cells = line.rstrip("\n").split(" ") if len(cells) == 4: # compatibility with pre-0.19.11 logs cells.append("0" if cells[2] in ["403", "404"] else "1") timestamp_str, host, status, request_time, dstack_replica_hit = cells + if not dstack_replica_hit: + # Nginx rejected the request before the server-level `set`, e.g. a + # malformed request answered with 400, so it never reached a replica + dstack_replica_hit = "0" timestamp = datetime.datetime.fromisoformat(timestamp_str) if timestamp < after: continue diff --git a/src/tests/_internal/proxy/gateway/services/test_stats.py b/src/tests/_internal/proxy/gateway/services/test_stats.py index f949178a4..0873e64c5 100644 --- a/src/tests/_internal/proxy/gateway/services/test_stats.py +++ b/src/tests/_internal/proxy/gateway/services/test_stats.py @@ -92,6 +92,22 @@ }, id="ignores-replica-not-hit", ), + pytest.param( + # Nginx rejected the 400 requests before setting $dstack_replica_hit, + # so the flag is empty and the lines end with a space + "2024-12-06T12:08:01+00:00 srv.gtw.test 200 0.100 1\n" + "2024-12-06T12:08:02+00:00 srv.gtw.test 400 0.001 \n" + "2024-12-06T12:08:02+00:00 srv.gtw.test 400 0.002 \n" + "2024-12-06T12:08:03+00:00 srv.gtw.test 200 0.300 1\n", + { + "srv.gtw.test": { + 30: Stat(requests=0, request_time=0.0), + 60: Stat(requests=0, request_time=0.0), + 300: Stat(requests=2, request_time=0.2), + }, + }, + id="ignores-requests-rejected-before-routing", + ), pytest.param( dedent( """