Spaces:
Sleeping
Sleeping
| """Structured JSON logging for API Contract Validator. | |
| Outputs one JSON object per log record to stdout (visible in docker logs) | |
| and, when writable, to logs/episodes.jsonl for persistent episode history. | |
| """ | |
| import json | |
| import logging | |
| import os | |
| import sys | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| class _JsonFormatter(logging.Formatter): | |
| def format(self, record: logging.LogRecord) -> str: | |
| payload: dict = { | |
| "ts": datetime.now(timezone.utc).isoformat(), | |
| "level": record.levelname, | |
| "logger": record.name, | |
| "msg": record.getMessage(), | |
| } | |
| if record.exc_info: | |
| payload["exc"] = self.formatException(record.exc_info) | |
| return json.dumps(payload) | |
| def configure_logging() -> None: | |
| """Configure root logger: JSON to stdout + logs/episodes.jsonl.""" | |
| log_level = os.getenv("LOG_LEVEL", "INFO").upper() | |
| root = logging.getLogger() | |
| if root.handlers: | |
| return # already configured (e.g. during testing) | |
| root.setLevel(log_level) | |
| sh = logging.StreamHandler(sys.stdout) | |
| sh.setFormatter(_JsonFormatter()) | |
| root.addHandler(sh) | |
| log_dir = Path(os.getenv("LOG_DIR", "logs")) | |
| try: | |
| log_dir.mkdir(parents=True, exist_ok=True) | |
| fh = logging.FileHandler(log_dir / "episodes.jsonl", encoding="utf-8") | |
| fh.setFormatter(_JsonFormatter()) | |
| root.addHandler(fh) | |
| except OSError: | |
| pass # read-only filesystem (HF Spaces free tier) β stdout only | |