feat: add telemetry foundation

This commit is contained in:
2026-06-02 14:21:17 +01:00
parent 8222660a3c
commit eb30450f34
4 changed files with 213 additions and 1 deletions
+78
View File
@@ -0,0 +1,78 @@
from __future__ import annotations
import json
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from pathlib import Path
@dataclass
class TelemetryEvent:
"""A single structured telemetry event."""
timestamp: str
event_type: str
target: str
details: dict = field(default_factory=dict)
def to_dict(self) -> dict:
return asdict(self)
def _session_log_path(root: Path) -> Path:
"""Return the path to the session-log.jsonl file under .rdb/."""
rdb_dir = root / ".rdb"
rdb_dir.mkdir(parents=True, exist_ok=True)
return rdb_dir / "session-log.jsonl"
def record_event(root: Path, event_type: str, target: str, details: dict | None = None) -> TelemetryEvent:
"""Record a telemetry event to the session log.
Creates the .rdb/session-log.jsonl file if it does not exist.
Each call appends one JSON line to the file.
Args:
root: Project root directory.
event_type: Category of event, e.g. 'command', 'task', 'guardrail'.
target: The entity the event relates to, e.g. 'rdb prompt'.
details: Optional extra key-value pairs for context.
Returns:
The TelemetryEvent that was recorded.
"""
event = TelemetryEvent(
timestamp=datetime.now(timezone.utc).isoformat(),
event_type=event_type,
target=target,
details=details or {},
)
log_path = _session_log_path(root)
with open(log_path, "a", encoding="utf-8") as f:
f.write(json.dumps(event.to_dict()) + "\n")
return event
def read_events(root: Path) -> list[TelemetryEvent]:
"""Read all events from the session log.
Returns an empty list if the log does not yet exist or is empty.
Malformed lines are silently skipped.
"""
log_path = _session_log_path(root)
if not log_path.exists():
return []
events: list[TelemetryEvent] = []
for line in log_path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
events.append(TelemetryEvent(**data))
except (json.JSONDecodeError, TypeError):
pass
return events