""" Утилиты для контекстного логирования """ from typing import Any, Optional, Dict, Union from aiogram.types import Message, CallbackQuery, User from services.infrastructure.logger import get_logger class LoggingContext: """Контекст для логирования с дополнительной информацией""" def __init__(self, module_name: str): self.logger = get_logger(module_name) self.context_data = {} def add_context(self, key: str, value: Any) -> 'LoggingContext': """Добавить данные в контекст""" self.context_data[key] = value return self def log_info(self, message: str, **kwargs): """Логирование с контекстом""" context_str = self._format_context() full_message = f"{message}{context_str}" self.logger.info(full_message, **kwargs) def log_warning(self, message: str, **kwargs): """Логирование предупреждения с контекстом""" context_str = self._format_context() full_message = f"{message}{context_str}" self.logger.warning(full_message, **kwargs) def log_error(self, message: str, **kwargs): """Логирование ошибки с контекстом""" context_str = self._format_context() full_message = f"{message}{context_str}" self.logger.error(full_message, **kwargs) def _format_context(self) -> str: """Форматирование контекстных данных""" if not self.context_data: return "" context_parts = [f"{k}={v}" for k, v in self.context_data.items()] return f" | {', '.join(context_parts)}" def get_logging_context(module_name: str) -> LoggingContext: """Получить контекст логирования для модуля""" return LoggingContext(module_name) def log_user_action( logger, action: str, user: Union[User, Message, CallbackQuery, int], additional_info: Optional[Dict[str, Any]] = None ): """ Логирование действий пользователя Args: logger: Логгер action: Действие пользователя user: Объект пользователя, сообщение, callback или user_id additional_info: Дополнительная информация """ user_id = _extract_user_id(user) user_info = _extract_user_info(user) context_parts = [f"user_id={user_id}"] if user_info: context_parts.append(f"user_info={user_info}") if additional_info: for key, value in additional_info.items(): context_parts.append(f"{key}={value}") context_str = f" | {', '.join(context_parts)}" if context_parts else "" logger.info(f"👤 {action}{context_str}") def log_business_operation( logger, operation: str, entity_type: str, entity_id: Optional[Union[int, str]] = None, additional_info: Optional[Dict[str, Any]] = None ): """ Логирование бизнес-операций Args: logger: Логгер operation: Операция (create, update, delete, etc.) entity_type: Тип сущности (question, user, etc.) entity_id: ID сущности additional_info: Дополнительная информация """ context_parts = [f"operation={operation}", f"entity_type={entity_type}"] if entity_id is not None: context_parts.append(f"entity_id={entity_id}") if additional_info: for key, value in additional_info.items(): context_parts.append(f"{key}={value}") context_str = f" | {', '.join(context_parts)}" logger.info(f"📊 Бизнес-операция: {operation} {entity_type}{context_str}") def log_fsm_event( logger, event: str, state: Optional[str] = None, user_id: Optional[int] = None, additional_info: Optional[Dict[str, Any]] = None ): """ Логирование FSM событий Args: logger: Логгер event: Событие FSM state: Текущее состояние user_id: ID пользователя additional_info: Дополнительная информация """ context_parts = [f"event={event}"] if state: context_parts.append(f"state={state}") if user_id: context_parts.append(f"user_id={user_id}") if additional_info: for key, value in additional_info.items(): context_parts.append(f"{key}={value}") context_str = f" | {', '.join(context_parts)}" logger.info(f"🔄 FSM: {event}{context_str}") def log_performance( logger, operation: str, duration: float, additional_info: Optional[Dict[str, Any]] = None ): """ Логирование производительности Args: logger: Логгер operation: Операция duration: Время выполнения в секундах additional_info: Дополнительная информация """ context_parts = [f"duration={duration:.3f}s"] if additional_info: for key, value in additional_info.items(): context_parts.append(f"{key}={value}") context_str = f" | {', '.join(context_parts)}" logger.info(f"⏱️ Производительность: {operation}{context_str}") def _extract_user_id(user: Union[User, Message, CallbackQuery, int]) -> int: """Извлечение user_id из различных объектов""" if isinstance(user, int): return user elif isinstance(user, User): return user.id elif isinstance(user, (Message, CallbackQuery)): return user.from_user.id else: return 0 def _extract_user_info(user: Union[User, Message, CallbackQuery, int]) -> Optional[str]: """Извлечение информации о пользователе""" if isinstance(user, int): return None elif isinstance(user, User): return f"{user.first_name or ''} {user.last_name or ''}".strip() or user.username or "Unknown" elif isinstance(user, (Message, CallbackQuery)): user_obj = user.from_user return f"{user_obj.first_name or ''} {user_obj.last_name or ''}".strip() or user_obj.username or "Unknown" else: return None # Удобные функции для быстрого логирования def log_question_created(logger, question_id: int, from_user_id: int, to_user_id: int): """Логирование создания вопроса""" log_business_operation( logger, "create", "question", question_id, {"from_user_id": from_user_id, "to_user_id": to_user_id} ) def log_question_answered(logger, question_id: int, user_id: int): """Логирование ответа на вопрос""" log_business_operation( logger, "answer", "question", question_id, {"user_id": user_id} ) def log_user_created(logger, user_id: int, username: Optional[str] = None): """Логирование создания пользователя""" additional_info = {"username": username} if username else None log_business_operation( logger, "create", "user", user_id, additional_info ) def log_user_blocked(logger, user_id: int, reason: Optional[str] = None): """Логирование блокировки пользователя""" additional_info = {"reason": reason} if reason else None log_business_operation( logger, "block", "user", user_id, additional_info )