"""File logging for WESP admin server-log viewer (SERVER_LOG_PATH).""" from __future__ import annotations import logging from datetime import UTC, datetime from pathlib import Path from typing import Any from app.core.config import settings _LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" def server_log_path() -> Path: return Path(settings.server_log_path) def ensure_server_log_file() -> Path: path = server_log_path() path.parent.mkdir(parents=True, exist_ok=True) if not path.is_file(): started = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ") path.write_text(f"{started} [INFO] compton.api: server log initialized\n", encoding="utf-8") return path.resolve() def build_uvicorn_log_config() -> dict[str, Any]: log_path = str(ensure_server_log_file()) return { "version": 1, "disable_existing_loggers": False, "formatters": { "default": { "format": _LOG_FORMAT, }, }, "handlers": { "file": { "class": "logging.FileHandler", "filename": log_path, "encoding": "utf-8", "formatter": "default", }, "console": { "class": "logging.StreamHandler", "formatter": "default", }, }, "loggers": { "uvicorn": {"handlers": ["file", "console"], "level": settings.log_level, "propagate": False}, "uvicorn.error": {"handlers": ["file", "console"], "level": settings.log_level, "propagate": False}, "uvicorn.access": {"handlers": ["file", "console"], "level": "INFO", "propagate": False}, }, "root": {"handlers": ["file", "console"], "level": settings.log_level}, } def append_server_log_line(message: str, level: str = "INFO") -> None: path = ensure_server_log_file() ts = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ") with path.open("a", encoding="utf-8") as fh: fh.write(f"{ts} [{level}] compton.api: {message}\n")