"""Logging setup for AYN Antivirus. Provides a one-call ``setup_logging()`` function that configures a rotating file handler and an optional console handler with consistent formatting across the entire application. """ from __future__ import annotations import logging import os import sys from logging.handlers import RotatingFileHandler from pathlib import Path from typing import Optional from ayn_antivirus.constants import DEFAULT_LOG_PATH # --------------------------------------------------------------------------- # Format # --------------------------------------------------------------------------- _LOG_FORMAT = "[%(asctime)s] %(levelname)s %(name)s: %(message)s" _DATE_FORMAT = "%Y-%m-%d %H:%M:%S" # Rotating handler defaults. _MAX_BYTES = 10 * 1024 * 1024 # 10 MB _BACKUP_COUNT = 5 def setup_logging( log_dir: str | Path = DEFAULT_LOG_PATH, level: int | str = logging.INFO, console: bool = True, filename: str = "ayn-antivirus.log", ) -> logging.Logger: """Configure the root ``ayn_antivirus`` logger. Parameters ---------- log_dir: Directory for the rotating log file. Created automatically. level: Logging level (``logging.DEBUG``, ``"INFO"``, etc.). console: If ``True``, also emit to stderr. filename: Name of the log file inside *log_dir*. Returns ------- logging.Logger The configured ``ayn_antivirus`` logger. """ if isinstance(level, str): level = getattr(logging, level.upper(), logging.INFO) root = logging.getLogger("ayn_antivirus") root.setLevel(level) # Avoid duplicate handlers on repeated calls. if root.handlers: return root formatter = logging.Formatter(_LOG_FORMAT, datefmt=_DATE_FORMAT) # --- Rotating file handler --- log_path = Path(log_dir) try: log_path.mkdir(parents=True, exist_ok=True) fh = RotatingFileHandler( str(log_path / filename), maxBytes=_MAX_BYTES, backupCount=_BACKUP_COUNT, encoding="utf-8", ) fh.setLevel(level) fh.setFormatter(formatter) root.addHandler(fh) except OSError: # If we can't write to the log dir, fall back to console only. pass # --- Console handler --- if console: ch = logging.StreamHandler(sys.stderr) ch.setLevel(level) ch.setFormatter(formatter) root.addHandler(ch) return root def get_logger(name: str) -> logging.Logger: """Return a child logger under the ``ayn_antivirus`` namespace. Example:: logger = get_logger("scanners.file") # → logging.getLogger("ayn_antivirus.scanners.file") """ return logging.getLogger(f"ayn_antivirus.{name}")