feat: API request/response logging with admin log viewer

- Add api_logs table (migration 0007) and ApiLog model
- Add web/lib/api_logger.py — httpx wrapper that records every outbound call
- Wire api_logger into vk_sync, vk_catalog, and connections test endpoints
- Add /admin/logs page with filters (service, method, status, time range, URL search) and expandable request/response detail
- Add "Логи" nav link for admin users

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mguschin
2026-05-12 22:00:14 +03:00
parent cad0b10fbb
commit 9960d760a0
10 changed files with 392 additions and 21 deletions

View File

@@ -5,9 +5,9 @@ for every connected user and upsert into vk_cached_* tables.
import logging
from datetime import datetime, timezone
import httpx
from celery import shared_task
import web.lib.api_logger as api_logger
from web.config import settings
from web.database import SessionLocal
from web.models.connections import VkCachedAlbum, VkCachedProduct, VkConnection
@@ -21,9 +21,9 @@ def _now() -> datetime:
return datetime.now(timezone.utc).replace(tzinfo=None)
def _vk_get(method: str, params: dict, token: str) -> dict:
def _vk_get(method: str, params: dict, token: str, user_id: int | None = None) -> dict:
params = {**params, "access_token": token, "v": settings.VK_API_VERSION}
r = httpx.get(f"{VK_API}/{method}", params=params, timeout=20)
r = api_logger.get(f"{VK_API}/{method}", user_id=user_id, params=params, timeout=20)
r.raise_for_status()
return r.json()
@@ -34,7 +34,7 @@ def _sync_user(db, user_id: int, token: str, group_id: str) -> None:
# ── albums ────────────────────────────────────────────────────────────────
try:
data = _vk_get("market.getAlbums", {"owner_id": owner_id, "count": 100}, token)
data = _vk_get("market.getAlbums", {"owner_id": owner_id, "count": 100}, token, user_id=user_id)
except Exception as e:
logger.warning("user=%s vk fetch albums failed: %s", user_id, e)
return
@@ -83,6 +83,7 @@ def _sync_user(db, user_id: int, token: str, group_id: str) -> None:
"market.get",
{"owner_id": owner_id, "count": 200, "offset": offset, "extended": 1},
token,
user_id=user_id,
)
except Exception as e:
logger.warning("user=%s vk fetch products (extended) failed: %s", user_id, e)