mapper + lint
This commit is contained in:
@@ -1,205 +1,95 @@
|
||||
# [MODULE_PATH] superset_tool.utils.logger
|
||||
# [FILE] logger.py
|
||||
# [SEMANTICS] logging, utils, ai‑friendly, infrastructure
|
||||
# <GRACE_MODULE id="superset_tool.utils.logger" name="logger.py">
|
||||
# @SEMANTICS: logging, utility, infrastructure, wrapper
|
||||
# @PURPOSE: Предоставляет универсальную обёртку над стандартным `logging.Logger` для унифицированного создания и управления логгерами с выводом в консоль и/или файл.
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [IMPORTS]
|
||||
# --------------------------------------------------------------
|
||||
# <IMPORTS>
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional, Any, Mapping
|
||||
# [END_IMPORTS]
|
||||
# </IMPORTS>
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Service('SupersetLogger')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Универсальная обёртка над ``logging.Logger``. Позволяет:
|
||||
• задавать уровень и вывод в консоль/файл,
|
||||
• передавать произвольные ``extra``‑поля,
|
||||
• использовать привычный API (info, debug, warning, error,
|
||||
critical, exception) без «падения» при неверных аргументах.
|
||||
:preconditions:
|
||||
- ``name`` – строка‑идентификатор логгера,
|
||||
- ``level`` – валидный уровень из ``logging``,
|
||||
- ``log_dir`` – при указании директория, куда будет писаться файл‑лог.
|
||||
:postconditions:
|
||||
- Создан полностью сконфигурированный ``logging.Logger`` без
|
||||
дублирующих обработчиков.
|
||||
"""
|
||||
# --- Начало кода модуля ---
|
||||
|
||||
# <ANCHOR id="SupersetLogger" type="Class">
|
||||
# @PURPOSE: Обёртка над `logging.Logger`, которая упрощает конфигурацию и использование логгеров.
|
||||
# @RELATION: WRAPS -> logging.Logger
|
||||
class SupersetLogger:
|
||||
"""
|
||||
:ivar logging.Logger logger: Внутренний стандартный логгер.
|
||||
:ivar bool propagate: Отключаем наследование записей, чтобы
|
||||
сообщения не «проваливались» выше.
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('__init__')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Конфигурировать базовый логгер, добавить обработчики
|
||||
консоли и/или файла, очистить прежние обработчики.
|
||||
:preconditions: Параметры валидны.
|
||||
:postconditions: ``self.logger`` готов к использованию.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "superset_tool",
|
||||
log_dir: Optional[Path] = None,
|
||||
level: int = logging.INFO,
|
||||
console: bool = True,
|
||||
) -> None:
|
||||
def __init__(self, name: str = "superset_tool", log_dir: Optional[Path] = None, level: int = logging.INFO, console: bool = True) -> None:
|
||||
# <ANCHOR id="SupersetLogger.__init__" type="Function">
|
||||
# @PURPOSE: Конфигурирует и инициализирует логгер, добавляя обработчики для файла и/или консоли.
|
||||
# @PARAM: name: str - Идентификатор логгера.
|
||||
# @PARAM: log_dir: Optional[Path] - Директория для сохранения лог-файлов.
|
||||
# @PARAM: level: int - Уровень логирования (e.g., `logging.INFO`).
|
||||
# @PARAM: console: bool - Флаг для включения вывода в консоль.
|
||||
# @POST: `self.logger` готов к использованию с настроенными обработчиками.
|
||||
self.logger = logging.getLogger(name)
|
||||
self.logger.setLevel(level)
|
||||
self.logger.propagate = False # ← не «прокидываем» записи выше
|
||||
self.logger.propagate = False
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
||||
|
||||
# ---- Очистка предыдущих обработчиков (важно при повторных инициализациях) ----
|
||||
if self.logger.hasHandlers():
|
||||
self.logger.handlers.clear()
|
||||
|
||||
# ---- Файловый обработчик (если указана директория) ----
|
||||
if log_dir:
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
timestamp = datetime.now().strftime("%Y%m%d")
|
||||
file_handler = logging.FileHandler(
|
||||
log_dir / f"{name}_{timestamp}.log", encoding="utf-8"
|
||||
)
|
||||
file_handler = logging.FileHandler(log_dir / f"{name}_{timestamp}.log", encoding="utf-8")
|
||||
file_handler.setFormatter(formatter)
|
||||
self.logger.addHandler(file_handler)
|
||||
|
||||
# ---- Консольный обработчик ----
|
||||
if console:
|
||||
console_handler = logging.StreamHandler(sys.stdout)
|
||||
console_handler.setFormatter(formatter)
|
||||
self.logger.addHandler(console_handler)
|
||||
# </ANCHOR id="SupersetLogger.__init__">
|
||||
|
||||
# [END_ENTITY]
|
||||
# <ANCHOR id="SupersetLogger._log" type="Function">
|
||||
# @PURPOSE: (Helper) Универсальный метод для вызова соответствующего уровня логирования.
|
||||
# @INTERNAL
|
||||
def _log(self, level_method: Any, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
level_method(msg, *args, extra=extra, exc_info=exc_info)
|
||||
# </ANCHOR id="SupersetLogger._log">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('_log')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Универсальная вспомогательная обёртка над
|
||||
``logging.Logger.<level>``. Принимает любые ``*args``
|
||||
(подстановочные параметры) и ``extra``‑словарь.
|
||||
:preconditions:
|
||||
- ``level_method`` – один из методов ``logger``,
|
||||
- ``msg`` – строка‑шаблон,
|
||||
- ``*args`` – значения для ``%``‑подстановок,
|
||||
- ``extra`` – пользовательские атрибуты (может быть ``None``).
|
||||
:postconditions: Запись в журнал выполнена.
|
||||
"""
|
||||
def _log(
|
||||
self,
|
||||
level_method: Any,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
if extra is not None:
|
||||
level_method(msg, *args, extra=extra, exc_info=exc_info)
|
||||
else:
|
||||
level_method(msg, *args, exc_info=exc_info)
|
||||
|
||||
# [END_ENTITY]
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('info')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня INFO.
|
||||
"""
|
||||
def info(
|
||||
self,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
# <ANCHOR id="SupersetLogger.info" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня INFO.
|
||||
def info(self, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
self._log(self.logger.info, msg, *args, extra=extra, exc_info=exc_info)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.info">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('debug')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня DEBUG.
|
||||
"""
|
||||
def debug(
|
||||
self,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
# <ANCHOR id="SupersetLogger.debug" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня DEBUG.
|
||||
def debug(self, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
self._log(self.logger.debug, msg, *args, extra=extra, exc_info=exc_info)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.debug">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('warning')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня WARNING.
|
||||
"""
|
||||
def warning(
|
||||
self,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
# <ANCHOR id="SupersetLogger.warning" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня WARNING.
|
||||
def warning(self, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
self._log(self.logger.warning, msg, *args, extra=extra, exc_info=exc_info)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.warning">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('error')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня ERROR.
|
||||
"""
|
||||
def error(
|
||||
self,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
# <ANCHOR id="SupersetLogger.error" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня ERROR.
|
||||
def error(self, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
self._log(self.logger.error, msg, *args, extra=extra, exc_info=exc_info)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.error">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('critical')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня CRITICAL.
|
||||
"""
|
||||
def critical(
|
||||
self,
|
||||
msg: str,
|
||||
*args: Any,
|
||||
extra: Optional[Mapping[str, Any]] = None,
|
||||
exc_info: bool = False,
|
||||
) -> None:
|
||||
# <ANCHOR id="SupersetLogger.critical" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня CRITICAL.
|
||||
def critical(self, msg: str, *args: Any, extra: Optional[Mapping[str, Any]] = None, exc_info: bool = False) -> None:
|
||||
self._log(self.logger.critical, msg, *args, extra=extra, exc_info=exc_info)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.critical">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [ENTITY: Method('exception')]
|
||||
# --------------------------------------------------------------
|
||||
"""
|
||||
:purpose: Записать сообщение уровня ERROR вместе с трассировкой
|
||||
текущего исключения (аналог ``logger.exception``).
|
||||
"""
|
||||
# <ANCHOR id="SupersetLogger.exception" type="Function">
|
||||
# @PURPOSE: Записывает сообщение уровня ERROR вместе с трассировкой стека текущего исключения.
|
||||
def exception(self, msg: str, *args: Any, **kwargs: Any) -> None:
|
||||
self.logger.exception(msg, *args, **kwargs)
|
||||
# [END_ENTITY]
|
||||
# </ANCHOR id="SupersetLogger.exception">
|
||||
# </ANCHOR id="SupersetLogger">
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# [END_FILE logger.py]
|
||||
# --------------------------------------------------------------
|
||||
# --- Конец кода модуля ---
|
||||
|
||||
# </GRACE_MODULE id="superset_tool.utils.logger">
|
||||
Reference in New Issue
Block a user