"""Structured JSON logging with rotation.""" import json import logging import logging.handlers from datetime import datetime, timezone from . import config class JSONFormatter(logging.Formatter): """Format log records as JSON lines.""" def format(self, record): entry = { "ts": datetime.now(timezone.utc).isoformat(), "level": record.levelname, "logger": record.name, "msg": record.getMessage(), } if record.exc_info and record.exc_info[0]: entry["exception"] = self.formatException(record.exc_info) # Include extra fields if present for key in ("stage", "source", "pr", "model", "cost", "event"): if hasattr(record, key): entry[key] = getattr(record, key) return json.dumps(entry) def setup_logging(): """Configure structured JSON logging with rotation.""" config.LOG_DIR.mkdir(parents=True, exist_ok=True) handler = logging.handlers.RotatingFileHandler( str(config.LOG_FILE), maxBytes=config.LOG_ROTATION_MAX_BYTES, backupCount=config.LOG_ROTATION_BACKUP_COUNT, ) handler.setFormatter(JSONFormatter()) # Also log to stderr for systemd journal console = logging.StreamHandler() console.setFormatter(logging.Formatter("%(name)s [%(levelname)s] %(message)s")) root = logging.getLogger() root.setLevel(logging.INFO) root.addHandler(handler) root.addHandler(console)