"""Bounded structured diagnostics for the two game-window supervisors.""" from __future__ import annotations from collections import Counter from collections.abc import Callable, Mapping, Sequence import json import math import os import re import sys import time WINDOW_DIAGNOSTICS_ENV = "PTLINUX_WINDOW_DIAGNOSTICS" WINDOW_DIAGNOSTICS_SESSION_ENV = "PTLINUX_WINDOW_DIAGNOSTICS_SESSION" WINDOW_DIAGNOSTIC_PREFIX = "PTLINUX_WINDOW_DIAGNOSTIC " WINDOW_DIAGNOSTIC_EVENT_LIMIT = 12 WINDOW_DIAGNOSTIC_LINE_LIMIT = 4096 WINDOW_DIAGNOSTIC_COMPONENTS = frozenset({"game_window", "gamescope_host"}) _DIAGNOSTIC_NAME_PATTERN = re.compile(r"[a-z][a-z0-9_]{0,63}\Z") _SESSION_ID_PATTERN = re.compile(r"[0-9a-f]{32}\Z") _TRUE_VALUES = frozenset({"1", "true", "yes"}) _MAX_DETAILS_DEPTH = 4 _MAX_DETAILS_ITEMS = 48 _MAX_STRING_CHARACTERS = 256 def window_diagnostics_enabled( environment: Mapping[str, str] | None = None, ) -> bool: env = os.environ if environment is None else environment return env.get(WINDOW_DIAGNOSTICS_ENV, "").strip().casefold() in _TRUE_VALUES class WindowDiagnosticRecorder: """Emit a few samples while retaining aggregate counts for session shutdown.""" def __init__( self, component: str, *, environment: Mapping[str, str] | None = None, monotonic: Callable[[], float] | None = None, ) -> None: if component not in WINDOW_DIAGNOSTIC_COMPONENTS: raise ValueError(f"unsupported window diagnostic component: {component}") env = os.environ if environment is None else environment session_id = env.get(WINDOW_DIAGNOSTICS_SESSION_ENV, "").strip().casefold() self.component = component self.enabled = window_diagnostics_enabled(env) self.session_id = ( session_id if _SESSION_ID_PATTERN.fullmatch(session_id) is not None else None ) self._monotonic = monotonic or time.monotonic self._started_at = self._monotonic() self._counts: Counter[str] = Counter() self._transitions: dict[str, object] = {} self._sequence = 0 self._emitted = 0 self._closed = False @property def accepts_samples(self) -> bool: return ( self.enabled and not self._closed and self._emitted < WINDOW_DIAGNOSTIC_EVENT_LIMIT ) def record(self, diagnostic: str, **details: object) -> None: if self._closed or _DIAGNOSTIC_NAME_PATTERN.fullmatch(diagnostic) is None: return self._sequence += 1 self._counts[diagnostic] += 1 if not self.enabled or self._emitted >= WINDOW_DIAGNOSTIC_EVENT_LIMIT: return self._emitted += 1 self._emit(diagnostic, self._sequence, details) def transition( self, key: str, value: object, diagnostic: str, **details: object, ) -> None: """Record one diagnostic only when the observed state changes.""" if self._closed or self._transitions.get(key, object()) == value: return self._transitions[key] = value self.record(diagnostic, **details) def close(self, **details: object) -> None: if self._closed: return self._closed = True if not self.enabled: return summary = { **details, "counts": dict(sorted(self._counts.items())), "sampled_events": self._emitted, "suppressed_events": max(0, self._sequence - self._emitted), } self._emit("session_summary", self._sequence + 1, summary) def _emit( self, diagnostic: str, sequence: int, details: Mapping[str, object], ) -> None: payload: dict[str, object] = { "schema": 1, "component": self.component, "diagnostic": diagnostic, "sequence": sequence, "elapsed_ms": max(0, round((self._monotonic() - self._started_at) * 1000)), "details": _bounded_value(details, depth=0), } if self.session_id is not None: payload["session_id"] = self.session_id try: encoded = json.dumps( payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True, ) if len(encoded.encode("utf-8")) > WINDOW_DIAGNOSTIC_LINE_LIMIT: payload["details"] = {"payload_truncated": True} encoded = json.dumps( payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True, ) print( f"{WINDOW_DIAGNOSTIC_PREFIX}{encoded}", file=sys.stderr, flush=True, ) except (OSError, TypeError, ValueError): return def parse_window_diagnostic(line: str) -> dict[str, object] | None: """Parse only launcher-generated, bounded window diagnostic records.""" marker_index = line.find(WINDOW_DIAGNOSTIC_PREFIX) if marker_index < 0: return None encoded = line[marker_index + len(WINDOW_DIAGNOSTIC_PREFIX):].strip() if not encoded or len(encoded.encode("utf-8")) > WINDOW_DIAGNOSTIC_LINE_LIMIT: return None try: payload = json.loads(encoded) except (json.JSONDecodeError, UnicodeError): return None if not isinstance(payload, dict) or payload.get("schema") != 1: return None component = payload.get("component") diagnostic = payload.get("diagnostic") sequence = payload.get("sequence") elapsed_ms = payload.get("elapsed_ms") details = payload.get("details") session_id = payload.get("session_id") if ( not isinstance(component, str) or component not in WINDOW_DIAGNOSTIC_COMPONENTS or not isinstance(diagnostic, str) or _DIAGNOSTIC_NAME_PATTERN.fullmatch(diagnostic) is None or not isinstance(sequence, int) or isinstance(sequence, bool) or sequence < 1 or not isinstance(elapsed_ms, int) or isinstance(elapsed_ms, bool) or elapsed_ms < 0 or not isinstance(details, dict) or ( session_id is not None and ( not isinstance(session_id, str) or _SESSION_ID_PATTERN.fullmatch(session_id) is None ) ) ): return None return { "schema": 1, "component": component, "diagnostic": diagnostic, "sequence": sequence, "elapsed_ms": elapsed_ms, "details": _bounded_value(details, depth=0), **({"session_id": session_id} if isinstance(session_id, str) else {}), } def _bounded_value(value: object, *, depth: int) -> object: if depth >= _MAX_DETAILS_DEPTH: return "" if value is None or isinstance(value, (bool, int)): return value if isinstance(value, float): return round(value, 3) if math.isfinite(value) else None if isinstance(value, str): return value[:_MAX_STRING_CHARACTERS] if isinstance(value, Mapping): result: dict[str, object] = {} for index, (raw_key, item) in enumerate(value.items()): if index >= _MAX_DETAILS_ITEMS: result["_truncated"] = True break key = str(raw_key)[:64] result[key] = _bounded_value(item, depth=depth + 1) return result if isinstance(value, Sequence) and not isinstance(value, (bytes, bytearray)): items = list(value[:_MAX_DETAILS_ITEMS]) return [_bounded_value(item, depth=depth + 1) for item in items] return f"<{type(value).__name__}>"