Files
AnonBot/services/infrastructure/logging_utils.py

228 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Утилиты для контекстного логирования
"""
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
)