import json
from typing import Any
from .timeutil import iso, utc_now
from .watcher import Watcher
def _row(row: Any) -> dict[str, Any]:
result = {key: row[key] for key in row.keys()} # noqa: SIM118 - sqlite Row exposes column names here
for key in ("evidence_json", "metadata_json"):
if result.get(key):
try:
result[key] = json.loads(result[key])
except json.JSONDecodeError:
pass
return result
def report_data(watcher: Watcher) -> dict[str, Any]:
return {"created_at": iso(utc_now()), "watcher": watcher.health(),
"jobs": [_row(row) for row in watcher.repository.status_rows()],
"workers": [_row(row) for row in watcher.repository.worker_rows()],
"agents": [_row(row) for row in watcher.repository.agent_rows()],
"collectors": [_row(row) for row in watcher.repository.collector_rows()],
"remote_events": [_row(row) for row in watcher.repository.remote_event_rows()],
"events": [_row(row) for row in watcher.repository.events()]}
def render_json(watcher: Watcher) -> str:
return json.dumps(report_data(watcher), ensure_ascii=False, indent=2, default=str)
def render_markdown(watcher: Watcher) -> str:
data = report_data(watcher)
health = data["watcher"]
lines = ["# Worker Watcher Report", "", f"Erstellt: `{data['created_at']}`", f"Watcher: **{health['watcher_status']}**", "",
"## Job-Summen", "", f"- healthy: {health['jobs_healthy']}", f"- degraded: {health['jobs_degraded']}",
f"- failed: {health['jobs_failed']}", f"- stale: {health['jobs_stale']}", f"- unknown: {health['jobs_unknown']}", "",
"## Aktuelle Jobs", "", "| Job | Instanz | Operational | Health | Observation | Severity |", "|---|---|---|---|---|---|"]
for job in data["jobs"]:
lines.append(f"| {job['job_key']} | {job['instance_key']} | {job['operational_state']} | {job['health_status']} | {job['observation_status']} | {job['severity']} |")
lines.extend(["", "## Collector-Läufe", "", "| Collector | Erfolg | Fehler |", "|---|---:|---|"])
for collector in data["collectors"][:20]:
lines.append(f"| {collector['collector_name']} | {bool(collector['success'])} | {collector.get('error_message') or ''} |")
lines.extend(["", "## Ausführungsorte", "", "| Agent | Umgebung | Host | Status |", "|---|---|---|---|"])
for agent in data["agents"]:
lines.append(f"| {agent['agent_key']} | {agent['environment']} | {agent['host']} | {agent['status']} |")
return "\n".join(lines) + "\n"