Riley
feat: Merge GPT-5 enhancements with working c72a240 base + restore crawler
cf9b3dc
Raw
History Blame Contribute Delete
1.94 kB
"""
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
@dataclass
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")