import subprocess
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any, Protocol
from ..config import CollectorConfig
from ..models import CollectorError, CollectorResult
from ..timeutil import utc_now
@dataclass(frozen=True, slots=True)
class CollectorContext:
now: datetime
host: str
config: CollectorConfig
base_dir: Path
class Collector(Protocol):
name: str
version: str
def collect(self, context: CollectorContext) -> CollectorResult:
...
class CommandRunner(Protocol):
def run(self, args: list[str], timeout_seconds: int) -> tuple[int, str, str]:
...
class SubprocessCommandRunner:
def run(self, args: list[str], timeout_seconds: int) -> tuple[int, str, str]:
completed = subprocess.run(args, capture_output=True, text=True, timeout=timeout_seconds, check=False)
return completed.returncode, completed.stdout, completed.stderr
def result(name: str, version: str, started: datetime, observations: list[Any], errors: list[CollectorError], diagnostics: dict[str, Any] | None = None) -> CollectorResult:
finished = utc_now()
return CollectorResult(name, version, started, finished, not errors, tuple(observations), tuple(errors), diagnostics or {})