remove infra.md.example, infra.md is the source of truth
This commit is contained in:
101
ayn-antivirus/ayn_antivirus/utils/logger.py
Normal file
101
ayn-antivirus/ayn_antivirus/utils/logger.py
Normal file
@@ -0,0 +1,101 @@
|
||||
"""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}")
|
||||
Reference in New Issue
Block a user