Skip to content

Commit c5b2060

Browse files
authored
fix runtime guard stale log filtering (#284)
1 parent 4628535 commit c5b2060

2 files changed

Lines changed: 99 additions & 7 deletions

File tree

scripts/cloud_run_runtime_guard.py

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ def _load_services() -> list[str]:
5858
for target in targets:
5959
if not isinstance(target, dict):
6060
continue
61+
if not _target_enabled(target):
62+
continue
6163
runtime_target = target.get("runtime_target") or target.get(
6264
"runtime_target_json"
6365
)
@@ -98,19 +100,43 @@ def _cloud_run_log_filter(service: str, since_text: str, region: str = "") -> st
98100
return " AND ".join(parts)
99101

100102

103+
def _service_job_aliases(service: str) -> list[str]:
104+
service_name = str(service or "").strip()
105+
if not service_name:
106+
return []
107+
aliases = [service_name]
108+
if service_name.endswith("-service"):
109+
aliases.append(service_name.removesuffix("-service"))
110+
return list(dict.fromkeys(aliases))
111+
112+
101113
def _scheduler_job_pattern_for_services(services: list[str]) -> str:
102114
candidates: list[str] = []
103115
for service in services:
104-
service_name = str(service or "").strip()
105-
if not service_name:
106-
continue
107-
candidates.append(service_name)
108-
if service_name.endswith("-service"):
109-
candidates.append(service_name.removesuffix("-service"))
116+
candidates.extend(_service_job_aliases(service))
110117
unique = list(dict.fromkeys(candidates))
111118
return "|".join(re.escape(candidate) for candidate in unique)
112119

113120

121+
def _entry_job_name(entry: dict[str, Any]) -> str:
122+
labels = _labels(entry)
123+
return str(labels.get("job_id") or labels.get("job_name") or "")
124+
125+
126+
def _scheduler_entry_since(
127+
entry: dict[str, Any],
128+
service_since_by_name: dict[str, dt.datetime],
129+
fallback: dt.datetime,
130+
) -> dt.datetime:
131+
job_name = _entry_job_name(entry)
132+
matches = [
133+
service_since
134+
for service, service_since in service_since_by_name.items()
135+
if any(alias and alias in job_name for alias in _service_job_aliases(service))
136+
]
137+
return max(matches) if matches else fallback
138+
139+
114140
def _run_gcloud(args: list[str]) -> subprocess.CompletedProcess[str]:
115141
return subprocess.run(args, text=True, capture_output=True, check=False)
116142

@@ -197,6 +223,27 @@ def _runtime_target(target: dict[str, Any]) -> dict[str, Any]:
197223
return runtime_target if isinstance(runtime_target, dict) else {}
198224

199225

226+
def _coerce_bool(value: Any, default: bool) -> bool:
227+
if value is None:
228+
return default
229+
if isinstance(value, bool):
230+
return value
231+
text = str(value).strip().lower()
232+
if not text:
233+
return default
234+
return text in {"1", "true", "yes", "y", "on"}
235+
236+
237+
def _target_enabled(target: dict[str, Any]) -> bool:
238+
runtime_target = _runtime_target(target)
239+
for key in ("runtime_target_enabled", "RUNTIME_TARGET_ENABLED"):
240+
if key in target:
241+
return _coerce_bool(target.get(key), True)
242+
if key in runtime_target:
243+
return _coerce_bool(runtime_target.get(key), True)
244+
return True
245+
246+
200247
def _target_service_names(target: dict[str, Any]) -> list[str]:
201248
runtime_target = _runtime_target(target)
202249
for key in ("service", "service_name", "cloud_run_service"):
@@ -441,6 +488,7 @@ def main() -> int:
441488
issues: list[str] = []
442489
details: list[str] = []
443490
success_count = 0
491+
service_since_by_name: dict[str, dt.datetime] = {}
444492

445493
try:
446494
services = _load_services()
@@ -454,6 +502,7 @@ def main() -> int:
454502

455503
for service in services:
456504
service_since = _cloud_run_log_since(project, service, since) if ignore_pre_ready_logs else since
505+
service_since_by_name[service] = service_since
457506
service_since_text = _format_timestamp(service_since)
458507
log_filter = _cloud_run_log_filter(service, service_since_text, _region_for_service(service))
459508
try:
@@ -483,7 +532,15 @@ def main() -> int:
483532
for entry in entries
484533
if regex.search(str(_labels(entry).get("job_id") or _labels(entry).get("job_name") or ""))
485534
]
486-
failures = [entry for entry in entries if _is_failure(entry)]
535+
failures = []
536+
for entry in entries:
537+
if not _is_failure(entry):
538+
continue
539+
entry_timestamp = _parse_timestamp(entry.get("timestamp"))
540+
entry_since = _scheduler_entry_since(entry, service_since_by_name, since)
541+
if entry_timestamp and entry_timestamp < entry_since:
542+
continue
543+
failures.append(entry)
487544
if failures:
488545
issues.append(f"{len(failures)} Cloud Scheduler failure log(s)")
489546
details.extend(_summarize(entry) for entry in failures[:5])

tests/test_cloud_run_runtime_guard.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,38 @@ def test_region_for_service_prefers_target_region(monkeypatch):
151151
)
152152

153153
assert guard._region_for_service("longbridge-quant-hk-service") == "asia-east1"
154+
155+
156+
def test_load_services_ignores_disabled_runtime_targets(monkeypatch):
157+
monkeypatch.delenv("RUNTIME_GUARD_CLOUD_RUN_SERVICES", raising=False)
158+
monkeypatch.delenv("CLOUD_RUN_SERVICES", raising=False)
159+
monkeypatch.delenv("CLOUD_RUN_SERVICE", raising=False)
160+
monkeypatch.setenv(
161+
"CLOUD_RUN_SERVICE_TARGETS_JSON",
162+
json.dumps(
163+
{
164+
"targets": [
165+
{"service": "enabled-service", "RUNTIME_TARGET_ENABLED": "true"},
166+
{"service": "disabled-service", "RUNTIME_TARGET_ENABLED": "false"},
167+
{"service": "disabled-lower-service", "runtime_target_enabled": "false"},
168+
]
169+
}
170+
),
171+
)
172+
173+
assert guard._load_services() == ["enabled-service"]
174+
175+
176+
def test_scheduler_entry_since_uses_matching_service_revision_window():
177+
fallback = dt.datetime(2026, 7, 1, 1, 0, tzinfo=dt.timezone.utc)
178+
service_since = dt.datetime(2026, 7, 1, 2, 0, tzinfo=dt.timezone.utc)
179+
entry = {"resource": {"labels": {"job_id": "enabled-service-scheduler"}}}
180+
181+
assert (
182+
guard._scheduler_entry_since(entry, {"enabled-service": service_since}, fallback)
183+
== service_since
184+
)
185+
assert (
186+
guard._scheduler_entry_since(entry, {"other-service": service_since}, fallback)
187+
== fallback
188+
)

0 commit comments

Comments
 (0)