#!/usr/bin/env python3 """Scan Unreal/client/server logs for critical 30-minute-soak failures.""" from __future__ import annotations import argparse import re import sys from pathlib import Path CRITICAL_PATTERNS = [ re.compile(pattern, re.IGNORECASE) for pattern in [ r"\bFatal\b", r"\bCritical\b", r"\bCrash\b", r"\bAssert(?:ion)?\b", r"\bEnsure condition failed\b", r"\bUnhandled Exception\b", r"\bAccess violation\b", r"\bLogOutputDevice:\s*Error\b", r"\bLogWindows:\s*Error\b", r"\bLogLinux:\s*Error\b", r"\bCallstack\b", ] ] # Keep this narrow. Add entries only for known benign engine noise with a commit # note explaining why the line is allowed. ALLOWLIST_PATTERNS = [ re.compile(r"LogWindows: Failed to load 'aqProf.dll'", re.IGNORECASE), re.compile(r"LogWindows: Failed to load 'VtuneApi\.dll'", re.IGNORECASE), ] DEFAULT_LOG_SUFFIXES = {".log", ".txt"} def iter_log_files(paths: list[Path]) -> list[Path]: files: list[Path] = [] for path in paths: if path.is_dir(): files.extend( candidate for candidate in path.rglob("*") if candidate.is_file() and candidate.suffix.lower() in DEFAULT_LOG_SUFFIXES ) elif path.is_file(): files.append(path) else: raise FileNotFoundError(f"Log path does not exist: {path}") return sorted(set(files)) def is_allowed(line: str) -> bool: return any(pattern.search(line) for pattern in ALLOWLIST_PATTERNS) def is_critical(line: str) -> bool: return any(pattern.search(line) for pattern in CRITICAL_PATTERNS) and not is_allowed(line) def scan_file(path: Path) -> list[tuple[int, str]]: matches: list[tuple[int, str]] = [] with path.open("r", encoding="utf-8", errors="replace") as handle: for line_number, line in enumerate(handle, start=1): if is_critical(line): matches.append((line_number, line.rstrip())) return matches def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("paths", nargs="+", type=Path, help="Log files or directories to scan.") args = parser.parse_args() log_files = iter_log_files(args.paths) if not log_files: print("ERROR: no .log or .txt files found to scan.", file=sys.stderr) return 2 failures: list[str] = [] for log_file in log_files: matches = scan_file(log_file) for line_number, line in matches: failures.append(f"{log_file}:{line_number}: {line}") if failures: print("FAILED: critical log spam detected.") for failure in failures[:200]: print(failure) if len(failures) > 200: print(f"... {len(failures) - 200} additional matches suppressed") return 1 print(f"OK: scanned {len(log_files)} log file(s); no critical log spam detected.") return 0 if __name__ == "__main__": raise SystemExit(main())