homelab-codex-ws/services/ha-diag-agent/src/ha_diag/event_emitter.py

62 lines
1.9 KiB
Python
Raw Normal View History

from __future__ import annotations
import json
import re
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
from .models import EventRecord
class EventEmitter:
"""Writes atomic JSON event files to the events directory."""
def __init__(
self, events_dir: Path, node_name: str, location_tag: str = ""
) -> None:
self._events_dir = events_dir
self._node_name = node_name
self._location_tag = location_tag
self._seq = 0
events_dir.mkdir(parents=True, exist_ok=True)
def _make_id(self, event_type: str, service: str) -> str:
# Sequence suffix guarantees uniqueness even when multiple events of the
# same type are emitted within the same millisecond.
self._seq += 1
ts = int(time.time())
svc_slug = re.sub(r"[^a-z0-9]", "-", (service or "ha").lower())[:32].strip("-")
return f"evt-{self._node_name}-{ts}-{event_type}-{svc_slug}-{self._seq}"
def emit(
self,
event_type: str,
severity: str,
service: str,
message: str,
payload: dict[str, Any] | None = None,
) -> str:
event_id = self._make_id(event_type, service)
merged: dict[str, Any] = {}
if self._location_tag:
merged["location_tag"] = self._location_tag
merged.update(payload or {})
record = EventRecord(
id=event_id,
timestamp=int(time.time()),
date=datetime.now(timezone.utc).isoformat(),
type=event_type,
severity=severity,
node=self._node_name,
service=service,
message=message,
payload=merged,
)
path = self._events_dir / f"{event_id}.json"
tmp = path.with_suffix(".tmp")
tmp.write_text(json.dumps(record.model_dump(), indent=2))
tmp.rename(path)
return event_id