diff --git a/api/src/app.py b/api/src/app.py index 8f72817..6b42fc4 100644 --- a/api/src/app.py +++ b/api/src/app.py @@ -13,7 +13,8 @@ middleware не подключается), healthcheck (uptime, version, nats: o `recognition.result` (ack и результаты сервисов) обрабатывает inbox `handle_message` того же модуля с фабрикой сессий приложения (inbox меняет задание и статус файла; маппинг результата в доменные таблицы — отдельный цикл, Срез 2c D-1). Остановка: фоновые задачи обмена → NATS → S3 → SMB → пул соединений БД; каждый шаг независим — ошибка одного -логируется и не отменяет остальные. +логируется и не отменяет остальные. Логгер настраивает `setup_logger` при импорте модуля: без значений локальных +переменных в трейсбеках (#63). """ import asyncio @@ -41,6 +42,7 @@ from src.api.router import API_PREFIX, build_api_router from src.core.clients import S3Storage from src.core.config import Settings, get_settings from src.core.exception_handlers import register_exception_handlers +from src.core.logger import setup_logger from src.core.nats import MessageHandler, NatsConnection from src.db.db import async_session_maker, engine, session_transaction from src.services.recognition_exchange import ExchangeTasks, handle_message @@ -51,6 +53,10 @@ settings = get_settings() VERSION = settings.VERSION UP_TIME = datetime.now(UTC) +# Свой обработчик loguru вместо стандартного: diagnose=False — значения локальных переменных не попадают в +# трейсбеки (#63) +setup_logger(level="DEBUG" if settings.DEBUG else "INFO") + # --- РАИСА: защищённый API (только вне DEBUG) --------------------------------------------------- protected_middleware_available = False diff --git a/api/tests/test_app.py b/api/tests/test_app.py index c739343..3436cc6 100644 --- a/api/tests/test_app.py +++ b/api/tests/test_app.py @@ -5,8 +5,11 @@ import asyncio import importlib +import subprocess +import sys import threading from http import HTTPStatus +from pathlib import Path from types import SimpleNamespace from typing import Any @@ -701,3 +704,48 @@ async def test_forwarded_for_only_from_trusted_proxy(tmp_path: Any, trusted: str def test_forwarded_allow_ips_default_is_loopback() -> None: assert Settings.model_fields["FORWARDED_ALLOW_IPS"].default == "127.0.0.1" + + +# --- Логгер: значения локальных переменных не попадают в лог (#63) ---------------------------------------------------- + +_LOG_EXCEPTION_SCRIPT = """ +import importlib +import os +import sys + +from loguru import logger + +sys.path.insert(0, os.getcwd()) +importlib.import_module("src.app") + + +def fail(): + secret = "local-secret-value" + raise ValueError("boom" if secret else "") + + +try: + fail() +except ValueError: + logger.exception("ошибка") +logger.complete() +""" + + +def test_app_import_logs_exceptions_without_local_values(tmp_path: Path) -> None: + """Импорт приложения настраивает loguru через setup_logger (diagnose=False): трейсбек есть, значений локальных + переменных в нём нет. Отдельный процесс — тесты перенастраивают обработчики loguru, здесь нужен чистый импорт. + Скрипт — файлом: без исходника (`python -c`) loguru не аннотирует строки и тест прошёл бы и с diagnose=True.""" + script = tmp_path / "log_exception.py" + script.write_text(_LOG_EXCEPTION_SCRIPT) + result = subprocess.run( + [sys.executable, str(script)], + cwd=Path(__file__).resolve().parents[1], + capture_output=True, + text=True, + timeout=60, + check=True, + ) + output = result.stdout + result.stderr + assert "ValueError: boom" in output + assert "local-secret-value" not in output