Merge pull request 'fix(backend): emit app.* INFO logs to stdout on the API process (#1926)' (#1941) from fix/1926-app-log-stdout into main
This commit is contained in:
commit
fc61fee15e
2 changed files with 48 additions and 0 deletions
|
|
@ -48,6 +48,24 @@ from app.observability.sentry_scrub import scrub_sensitive_query
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# App-level логи в stdout контейнера (#1926 observability). По умолчанию у app.*
|
||||
# логгеров нет StreamHandler → их INFO теряется (в `docker logs` видны только
|
||||
# uvicorn-логгеры), поэтому полезные строки (напр. "OSRM road-distance applied",
|
||||
# RBAC, analyze) невидимы при отладке на VPS. Вешаем один StreamHandler на корневой
|
||||
# "app" логгер на уровне APP_LOG_LEVEL (default INFO). propagate оставляем True →
|
||||
# Sentry/GlitchTip LoggingIntegration (хендлер на root) продолжает получать
|
||||
# breadcrumbs/events. Двойного stdout нет: у root своего stdout-хендлера нет.
|
||||
# Идемпотентно (маркер _gd_app_stream — guard против дубля при reload/повторном
|
||||
# импорте). Только API-процесс (main.py); worker (celery_app.py) НЕ трогаем —
|
||||
# там loader'ы чатятся per-sync, INFO бы зашумил.
|
||||
_app_logger = logging.getLogger("app")
|
||||
_app_logger.setLevel(getattr(logging, os.getenv("APP_LOG_LEVEL", "INFO").upper(), logging.INFO))
|
||||
if not any(getattr(_h, "_gd_app_stream", False) for _h in _app_logger.handlers):
|
||||
_stream = logging.StreamHandler()
|
||||
_stream.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s"))
|
||||
_stream._gd_app_stream = True # type: ignore[attr-defined] # idempotency marker
|
||||
_app_logger.addHandler(_stream)
|
||||
|
||||
# Инициализируем SDK до создания FastAPI app, чтобы все инструменты
|
||||
# (middleware, маршруты) видели активный client с самого старта процесса.
|
||||
# GlitchTip не поддерживает profiling — profiles_sample_rate=0.0.
|
||||
|
|
|
|||
30
backend/tests/test_app_logging.py
Normal file
30
backend/tests/test_app_logging.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""#1926 observability: app-logger StreamHandler в main.py (логи app.* в stdout).
|
||||
|
||||
Без него INFO от `logging.getLogger("app.*")` терялся (в `docker logs` видны были
|
||||
только uvicorn-логгеры), и полезные строки (OSRM road-distance applied, RBAC,
|
||||
analyze) были невидимы при отладке на VPS.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def test_app_logger_has_stdout_handler() -> None:
|
||||
import app.main # noqa: F401 — module-level logging setup выполняется на импорте
|
||||
|
||||
app_logger = logging.getLogger("app")
|
||||
|
||||
# Уровень INFO (default APP_LOG_LEVEL).
|
||||
assert app_logger.level == logging.INFO
|
||||
|
||||
# Ровно один маркированный StreamHandler — идемпотентность (повторный импорт
|
||||
# не плодит дубли).
|
||||
marked = [h for h in app_logger.handlers if getattr(h, "_gd_app_stream", False)]
|
||||
assert len(marked) == 1
|
||||
assert isinstance(marked[0], logging.StreamHandler)
|
||||
|
||||
# propagate=True → Sentry/GlitchTip LoggingIntegration (хендлер на root)
|
||||
# продолжает получать breadcrumbs/events; stdout-дубля нет (у root своего
|
||||
# stdout-хендлера нет).
|
||||
assert app_logger.propagate is True
|
||||
Loading…
Add table
Reference in a new issue