This commit is contained in:
2026-08-31 15:11:52 +03:30
parent 236002a87c
commit 463b812e3e
63 changed files with 3254 additions and 1476 deletions
+60
View File
@@ -0,0 +1,60 @@
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