# [MODULE] Superset Tool Logger Utility # @contract: Этот модуль предоставляет утилиту для настройки логирования в приложении. # @semantic_layers: # - [CONFIG]: Настройка логгера. # - [UTILITY]: Вспомогательные функции. # @coherence: Модуль должен быть семантически когерентен со стандартной библиотекой `logging`. import logging import sys from datetime import datetime from pathlib import Path from typing import Optional # [CONSTANTS] class SupersetLogger: def __init__( self, name: str = "superset_tool", log_dir: Optional[Path] = None, level: int = logging.INFO, console: bool = True ): self.logger = logging.getLogger(name) self.logger.setLevel(level) formatter = logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) # Очищаем существующие обработчики if self.logger.handlers: for handler in self.logger.handlers[:]: self.logger.removeHandler(handler) # Файловый обработчик if log_dir: log_dir.mkdir(parents=True, exist_ok=True) file_handler = logging.FileHandler( log_dir / f"{name}_{self._get_timestamp()}.log" ) file_handler.setFormatter(formatter) self.logger.addHandler(file_handler) # Консольный обработчик if console: console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) self.logger.addHandler(console_handler) def _get_timestamp(self) -> str: return datetime.now().strftime("%Y%m%d") def info(self, message: str, extra: Optional[dict] = None, exc_info: bool = False): self.logger.info(message, extra=extra, exc_info=exc_info) def error(self, message: str, extra: Optional[dict] = None, exc_info: bool = False): self.logger.error(message, extra=extra, exc_info=exc_info) def warning(self, message: str, extra: Optional[dict] = None, exc_info: bool = False): self.logger.warning(message, extra=extra, exc_info=exc_info) def critical(self, message: str, extra: Optional[dict] = None, exc_info: bool = False): self.logger.critical(message, extra=extra, exc_info=exc_info) def debug(self, message: str, extra: Optional[dict] = None, exc_info: bool = False): self.logger.debug(message, extra=extra, exc_info=exc_info) def exception(self, message: str): self.logger.exception(message) def setup_logger(name: str, level: int = logging.INFO) -> logging.Logger: # [FUNCTION] setup_logger # [CONTRACT] """ Настраивает и возвращает логгер с заданным именем и уровнем. @pre: - `name` является непустой строкой. - `level` является допустимым уровнем логирования из модуля `logging`. @post: - Возвращает настроенный экземпляр `logging.Logger`. - Логгер имеет StreamHandler, выводящий в sys.stdout. - Форматтер логгера включает время, уровень, имя и сообщение. @side_effects: - Создает и добавляет StreamHandler к логгеру. @invariant: - Логгер с тем же именем всегда возвращает один и тот же экземпляр. """ # [CONFIG] Настройка логгера # [COHERENCE_CHECK_PASSED] Логика настройки соответствует описанию. logger = logging.getLogger(name) logger.setLevel(level) # Создание форматтера formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s') # Проверка наличия существующих обработчиков if not logger.handlers: # Создание StreamHandler для вывода в sys.stdout handler = logging.StreamHandler(sys.stdout) handler.setFormatter(formatter) logger.addHandler(handler) return logger