Merge pull request 'Логгер: вызывать setup_logger при импорте приложения (#18)' (#20) from feat/18-logger-diagnose into main

Reviewed-on: #20
This commit is contained in:
aep 2026-10-08 15:47:49 +03:00
commit 1e7027ba73
2 changed files with 52 additions and 0 deletions

View File

@ -10,6 +10,7 @@
HTTP-сервер жив. HTTP-сервер жив.
Остановка: отмена подключения, остановка воркера (задания в работе отменяются), закрытие NATS и S3. Остановка: отмена подключения, остановка воркера (задания в работе отменяются), закрытие NATS и S3.
- Объекты lifespan доступны в `app.state`: `worker`, `nats`, `storage`, `normalizer`, `health`. - Объекты lifespan доступны в `app.state`: `worker`, `nats`, `storage`, `normalizer`, `health`.
- При импорте модуля — `setup_logger` (без значений локальных переменных в трейсбеках), затем `app = create_app()`.
- `NATS_ENABLED=false` — подключения нет (`nats = disabled`), воркер запросов не получает (dev без NATS). - `NATS_ENABLED=false` — подключения нет (`nats = disabled`), воркер запросов не получает (dev без NATS).
""" """
@ -28,6 +29,7 @@ from src.core.clients import S3Storage
from src.core.config import Settings, get_settings from src.core.config import Settings, get_settings
from src.core.exception_handlers import register_exception_handlers from src.core.exception_handlers import register_exception_handlers
from src.core.health import HealthProvider from src.core.health import HealthProvider
from src.core.logger import setup_logger
from src.core.nats import NatsGateway from src.core.nats import NatsGateway
from src.core.worker import Worker from src.core.worker import Worker
from src.gateway import create_hotfolder from src.gateway import create_hotfolder
@ -116,4 +118,7 @@ def create_app(settings: Settings | None = None) -> FastAPI:
return app return app
# Свой обработчик loguru вместо стандартного: diagnose=False — значения локальных переменных не попадают в
# трейсбеки (#18)
setup_logger(level="DEBUG" if get_settings().DEBUG else "INFO")
app = create_app() app = create_app()

View File

@ -2,6 +2,8 @@
воркер). NATS и S3 не нужны: в тестах lifespan `NATS_ENABLED=false` либо методы `NatsGateway` подменены.""" воркер). NATS и S3 не нужны: в тестах lifespan `NATS_ENABLED=false` либо методы `NatsGateway` подменены."""
import asyncio import asyncio
import subprocess
import sys
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@ -228,3 +230,48 @@ def test_create_app_fails_on_broken_rules(tmp_path: Path) -> None:
def test_create_app_uses_ocr_normalizer() -> None: def test_create_app_uses_ocr_normalizer() -> None:
app = create_app(get_settings().model_copy(update={"SCAN_HOTFOLDER_PATH": "."})) app = create_app(get_settings().model_copy(update={"SCAN_HOTFOLDER_PATH": "."}))
assert isinstance(app.state.normalizer, OcrNormalizer) assert isinstance(app.state.normalizer, OcrNormalizer)
# --- Логгер: значения локальных переменных не попадают в лог (#18) ----------------------------------------------------
_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[2],
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