import time # مانیتورینگ خودکار همه‌ی فراخوانی‌های API — بدون نیازِ به هیچ تغییری توی # اپ فلاتر، چون توی همان سطحِ میدل‌ور جنگو کار می‌کند. کاربر از JWT توی # هدرِ Authorization (اگر باشد) استخراج می‌شود — در این لحظه هنوز # AuthenticationMiddleware کاربر واقعی را روی request نگذاشته (آن فقط برای # auth مبتنی‌بر session است، نه JWT)، پس خودمان با JWTAuthentication همان # توکن را می‌خوانیم. class ApiCallLoggingMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): start = time.monotonic() response = self.get_response(request) if request.path.startswith("/api/"): duration_ms = (time.monotonic() - start) * 1000 try: self._log(request, response, duration_ms) except Exception: # لاگ‌گیریِ مانیتورینگ هیچ‌وقت نباید پاسخِ واقعی به کاربر را # خراب کند. pass return response def _log(self, request, response, duration_ms): from .models import ApiCallLog ApiCallLog.objects.create( user=self._resolve_user(request), method=request.method, path=request.path[:255], status_code=response.status_code, duration_ms=duration_ms, ip_address=self._client_ip(request), ) @staticmethod def _resolve_user(request): auth_header = request.META.get("HTTP_AUTHORIZATION", "") if not auth_header.startswith("Bearer "): return None try: from rest_framework_simplejwt.authentication import JWTAuthentication result = JWTAuthentication().authenticate(request) return result[0] if result else None except Exception: return None @staticmethod def _client_ip(request): forwarded = request.META.get("HTTP_X_FORWARDED_FOR") if forwarded: return forwarded.split(",")[0].strip() return request.META.get("REMOTE_ADDR") or None