102 lines
2.7 KiB
Python
102 lines
2.7 KiB
Python
"""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}")
|