feat: логирование вебхука до БД + файловый лог с ротацией
All checks were successful
CI / test (push) Successful in 47s

- Каждый входящий POST /ingress/grafana: INFO-строка (status, кол-во алертов,
  первые лейблы) и DEBUG-блок с полным JSON телом (до 8КБ)
  — видно даже если БД упала с 500
- LOG_FILE в .env / env: RotatingFileHandler 10MB×5 файлов
- LOG_LEVEL=debug теперь показывает полные тела вебхуков
- basicConfig уровень DEBUG (uvicorn.access / asyncio приглушены)

Made-with: Cursor
This commit is contained in:
Alexandr
2026-04-03 15:59:17 +03:00
parent 80645713a0
commit c9b97814a5
5 changed files with 86 additions and 8 deletions

View File

@ -82,6 +82,42 @@ def service_hint_from_grafana_body(body: dict, header_service: str | None) -> st
return None
def _log_incoming_webhook(body: object, raw: bytes, path_slug: str | None) -> None:
"""Логирует каждый входящий вебхук: краткое резюме INFO + полное тело DEBUG."""
slug_tag = f"[/{path_slug}]" if path_slug else "[/]"
raw_len = len(raw)
if not isinstance(body, dict):
logger.info("grafana webhook %s raw=%dB (non-dict body)", slug_tag, raw_len)
logger.debug("grafana webhook %s raw body: %s", slug_tag, raw[:4000].decode(errors="replace"))
return
alerts = body.get("alerts") or []
n_alerts = len(alerts) if isinstance(alerts, list) else 0
status = body.get("status", "?")
title = str(body.get("title") or body.get("ruleName") or "")[:120]
first_labels: dict = {}
if isinstance(alerts, list) and alerts and isinstance(alerts[0], dict):
first_labels = alerts[0].get("labels") or {}
logger.info(
"grafana webhook %s status=%s alerts=%d title=%r labels=%s raw=%dB",
slug_tag,
status,
n_alerts,
title,
json.dumps(first_labels, ensure_ascii=False)[:300],
raw_len,
)
try:
pretty = json.dumps(body, ensure_ascii=False, indent=2)
if len(pretty) > 8000:
pretty = pretty[:8000] + "\n…(обрезано)"
except Exception:
pretty = raw[:8000].decode(errors="replace")
logger.debug("grafana webhook %s full body:\n%s", slug_tag, pretty)
async def _grafana_webhook_impl(
request: Request,
pool,
@ -98,6 +134,10 @@ async def _grafana_webhook_impl(
body = json.loads(raw.decode() or "{}")
except json.JSONDecodeError:
body = {}
# Логируем входящий вебхук ДО любой обработки — чтобы видеть при любой ошибке
_log_incoming_webhook(body, raw, path_slug)
if not isinstance(body, dict):
body = {}
else: