Implement user-specific question numbering and update database schema. Added triggers for automatic question numbering and adjustments upon deletion. Enhanced CRUD operations to manage user_question_number effectively.
This commit is contained in:
227
services/infrastructure/logging_utils.py
Normal file
227
services/infrastructure/logging_utils.py
Normal file
@@ -0,0 +1,227 @@
|
||||
"""
|
||||
Утилиты для контекстного логирования
|
||||
"""
|
||||
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
|
||||
)
|
||||
Reference in New Issue
Block a user