Spaces:
Sleeping
Sleeping
| """ | |
| telemetry/logger.py — append-only JSONL logging for Q&A turns. | |
| Usage: | |
| from analyzer.telemetry.logger import QALogger | |
| log = QALogger("logs/chat.jsonl") | |
| log.write(user="find farming grants", intent="search", args={"keyword":"farming"}, | |
| answer_md="...", ok=True, latency_ms=321, meta={"model":"gpt-4.1-mini"}) | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import asdict, dataclass, field | |
| from pathlib import Path | |
| from typing import Any, Dict, Optional | |
| import json, os, time, threading, uuid, datetime as dt | |
| class QATurn: | |
| ts: str | |
| session_id: str | |
| turn_id: str | |
| user: str | |
| intent: str | |
| args: Dict[str, Any] = field(default_factory=dict) | |
| answer_md: str = "" | |
| ok: bool = True | |
| latency_ms: Optional[int] = None | |
| meta: Dict[str, Any] = field(default_factory=dict) | |
| class QALogger: | |
| def __init__(self, path: str | Path): | |
| self.path = Path(path) | |
| self.path.parent.mkdir(parents=True, exist_ok=True) | |
| self._lock = threading.Lock() | |
| self._session = os.getenv("CHAT_SESSION_ID") or str(uuid.uuid4()) | |
| def write(self, *, user: str, intent: str, args: Dict[str, Any], | |
| answer_md: str, ok: bool, latency_ms: Optional[int], | |
| meta: Optional[Dict[str, Any]] = None) -> None: | |
| turn = QATurn( | |
| ts=dt.datetime.utcnow().isoformat(timespec="seconds") + "Z", | |
| session_id=self._session, | |
| turn_id=str(uuid.uuid4()), | |
| user=str(user), | |
| intent=str(intent), | |
| args=args or {}, | |
| answer_md=str(answer_md or ""), | |
| ok=bool(ok), | |
| latency_ms=int(latency_ms) if latency_ms is not None else None, | |
| meta=meta or {}, | |
| ) | |
| line = json.dumps(asdict(turn), ensure_ascii=False) | |
| with self._lock: | |
| with open(self.path, "a", encoding="utf-8") as fh: | |
| fh.write(line + "\n") |