feat: improve operation diagnostics and API logging
This commit is contained in:
1 parent
aaea5b6f58
commit
2d743d2220
9 files changed
+272
-47
No files matched your search
@@ -28,7 +28,7 @@ from aiogram.types import (
|
||||
import payments
|
||||
import user_store
|
||||
|
||||
from apinex_client import APINEX_STT_URL, POST_HISTORY_CHAR_LIMIT, POST_HISTORY_LIMIT, classify_intent, create_tone_profile, extract_posts_from_images, extract_transcript, generate_ideas, generate_posts, transcribe_audio
|
||||
from apinex_client import APINEX_STT_URL, POST_HISTORY_CHAR_LIMIT, POST_HISTORY_LIMIT, classify_intent, create_tone_profile, current_operation_id, diagnostic_operation, extract_posts_from_images, extract_transcript, generate_ideas, generate_posts, transcribe_audio
|
||||
from help_message import WELCOME_RICH_HTML, help_plain_view, help_view, rich_to_plain
|
||||
from keyboards import MAIN_MENU_VALUE, main_menu_keyboard, mode_keyboard, resolve_button_text
|
||||
from payments import send_subscription_invoice
|
||||
@@ -167,18 +167,29 @@ def split_text(text: str, limit: int = 4000) -> list[str]:
|
||||
async def report_error(message: Message, stage: str, exc: Exception) -> None:
|
||||
detail = str(exc).strip()
|
||||
detail = re.sub(r"(?i)(?:sk-[A-Za-z0-9_-]{12,}|[0-9]{8,}:[A-Za-z0-9_-]{20,})", "[секрет скрыт]", detail)
|
||||
detail = re.sub(r"(?i)bearer\s+[^\s\"']+", "Bearer [секрет скрыт]", detail)
|
||||
detail = re.sub(r"(?i)(api[_-]?key|access[_-]?token|secret|password)(\s*[=:]\s*)[^\s,;\"']+", r"\1\2[секрет скрыт]", detail)
|
||||
detail = re.sub(r"https?://\S+", "[внешний сервис]", detail)
|
||||
detail = detail or "нет подробностей"
|
||||
operation_id = current_operation_id() or "-"
|
||||
user_id = message.from_user.id if message.from_user else "-"
|
||||
try:
|
||||
await message.answer(f"❌ Не получилось: {stage}. Попробуй ещё раз позже.")
|
||||
if is_development_environment():
|
||||
await message.answer(
|
||||
f"🧪 Dev-диагностика: {stage}. Причина: <code>{html.escape(detail[:240])}</code>",
|
||||
f"🧪 Dev-диагностика: {stage}. ID: <code>{operation_id}</code>. "
|
||||
f"Причина: <code>{html.escape(detail[:240])}</code>",
|
||||
parse_mode="HTML",
|
||||
)
|
||||
except Exception as send_exc:
|
||||
logger.error("Unable to report processing error: %s", type(send_exc).__name__)
|
||||
logger.error("User operation failed at %s (%s): %s", stage, type(exc).__name__, detail[:240])
|
||||
safe_exc = RuntimeError(f"{type(exc).__name__}: {detail[:2000]}")
|
||||
safe_exc.__traceback__ = exc.__traceback__
|
||||
logger.error(
|
||||
"User operation failed operation_id=%s user_id=%s stage=%s; traceback follows",
|
||||
operation_id, user_id, stage,
|
||||
exc_info=(RuntimeError, safe_exc, safe_exc.__traceback__),
|
||||
)
|
||||
|
||||
|
||||
async def notify_development_deploy(bot: Bot) -> None:
|
||||
@@ -517,6 +528,16 @@ async def _classify_and_respond(
|
||||
text: str,
|
||||
show_typing: bool = True,
|
||||
state: FSMContext | None = None,
|
||||
) -> None:
|
||||
with diagnostic_operation():
|
||||
await _classify_and_respond_inner(message, text, show_typing, state)
|
||||
|
||||
|
||||
async def _classify_and_respond_inner(
|
||||
message: Message,
|
||||
text: str,
|
||||
show_typing: bool = True,
|
||||
state: FSMContext | None = None,
|
||||
) -> None:
|
||||
if message.from_user is None:
|
||||
await message.answer("Не удалось определить пользователя.")
|
||||
@@ -660,17 +681,18 @@ async def _finish_media_group(key: tuple[int, str]) -> None:
|
||||
|
||||
async def _handle_image_message(message: Message, bot: Bot) -> None:
|
||||
await notify_development_deploy(bot)
|
||||
try:
|
||||
if message.media_group_id:
|
||||
messages = await _collect_media_group(message, bot)
|
||||
if messages[0].message_id != message.message_id:
|
||||
return
|
||||
else:
|
||||
messages = [message]
|
||||
async with typing_status(bot, message.chat.id):
|
||||
await _process_image_group(messages, bot)
|
||||
except Exception as exc:
|
||||
await report_error(message, "чтение скриншота или обновление ToV", exc)
|
||||
with diagnostic_operation():
|
||||
try:
|
||||
if message.media_group_id:
|
||||
messages = await _collect_media_group(message, bot)
|
||||
if messages[0].message_id != message.message_id:
|
||||
return
|
||||
else:
|
||||
messages = [message]
|
||||
async with typing_status(bot, message.chat.id):
|
||||
await _process_image_group(messages, bot)
|
||||
except Exception as exc:
|
||||
await report_error(message, "чтение скриншота или обновление ToV", exc)
|
||||
|
||||
|
||||
@router.message(F.photo | (F.document & F.document.mime_type.startswith("image/")))
|
||||
@@ -712,11 +734,12 @@ async def transcribe_voice(message: Message, bot: Bot, state: FSMContext) -> Non
|
||||
if not await require_mode(message, state, "generation"):
|
||||
return
|
||||
await notify_development_deploy(bot)
|
||||
try:
|
||||
async with typing_status(bot, message.chat.id):
|
||||
await _process_voice(message, bot, state)
|
||||
except Exception as exc:
|
||||
await report_error(message, "обработка голосового и генерация", exc)
|
||||
with diagnostic_operation():
|
||||
try:
|
||||
async with typing_status(bot, message.chat.id):
|
||||
await _process_voice(message, bot, state)
|
||||
except Exception as exc:
|
||||
await report_error(message, "обработка голосового и генерация", exc)
|
||||
|
||||
|
||||
@router.message(F.text & F.text.startswith("/"))
|
||||
|
||||
Reference in new issue
Block a user