Append-only JSONL store rotated daily.
| 180 | |
| 181 | |
| 182 | class FileTraceStorage(TraceStorage): |
| 183 | """Append-only JSONL store rotated daily.""" |
| 184 | |
| 185 | def __init__(self, base_dir: Path | None = None) -> None: |
| 186 | self._base_dir = base_dir or (data_dir() / "traces") |
| 187 | |
| 188 | def append(self, record: dict[str, Any]) -> None: |
| 189 | try: |
| 190 | self._base_dir.mkdir(parents=True, exist_ok=True, mode=0o700) |
| 191 | day = _date_str(float(record.get("timestamp", time.time()))) |
| 192 | path = self._base_dir / f"{day}.jsonl" |
| 193 | line = json.dumps(record, default=str, ensure_ascii=False) |
| 194 | with open(path, "a", encoding="utf-8") as f: |
| 195 | f.write(line + "\n") |
| 196 | try: |
| 197 | path.chmod(0o600) |
| 198 | except Exception: |
| 199 | pass |
| 200 | except Exception: |
| 201 | pass |
| 202 | |
| 203 | def load_recent_days( |
| 204 | self, days: int, *, now: float |
| 205 | ) -> list[dict[str, Any]]: |
| 206 | if not self._base_dir.exists(): |
| 207 | return [] |
| 208 | import datetime as _dt |
| 209 | end = _dt.datetime.fromtimestamp(now, tz=_dt.timezone.utc).date() |
| 210 | accepted = { |
| 211 | (end - _dt.timedelta(days=i)).strftime("%Y-%m-%d") |
| 212 | for i in range(max(1, days)) |
| 213 | } |
| 214 | files = sorted( |
| 215 | f for f in self._base_dir.glob("*.jsonl") if f.stem in accepted |
| 216 | ) |
| 217 | out: list[dict[str, Any]] = [] |
| 218 | for f in files: |
| 219 | try: |
| 220 | for line in f.read_text(encoding="utf-8").splitlines(): |
| 221 | line = line.strip() |
| 222 | if not line: |
| 223 | continue |
| 224 | try: |
| 225 | out.append(json.loads(line)) |
| 226 | except Exception: |
| 227 | continue |
| 228 | except Exception: |
| 229 | continue |
| 230 | return out |
| 231 | |
| 232 | def load_for_request( |
| 233 | self, request_id: str, timestamp: float |
| 234 | ) -> dict[str, Any] | None: |
| 235 | if not self._base_dir.exists(): |
| 236 | return None |
| 237 | import datetime as _dt |
| 238 | center = _dt.datetime.fromtimestamp(timestamp, tz=_dt.timezone.utc).date() |
| 239 | candidates = [ |
no outgoing calls