>>>
... import hashlib
... from uuid import uuid4
... from django.db import models
... from django.http import HttpResponse, HttpRequest
... from django.utils.translation import gettext_lazy as _
...
...
... def get_client_ip(request):
... x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
... if x_forwarded_for:
... ip = x_forwarded_for.split(',')[-1].strip()
... else:
... ip = request.META.get('REMOTE_ADDR')
... return ip
...
...
... def calculate_content_hash(request):
... if hasattr(request, 'body'):
... return hashlib.sha1(request.body).hexdigest()
...
...
... class HttpMethod(models.TextChoices):
... GET = 'GET', _('GET')
... POST = 'POST', _('POST')
... PATCH = 'PATCH', _('PATCH')
... PUT = 'PUT', _('PUT')
... HEAD = 'HEAD', _('HEAD')
... DELETE = 'DELETE', _('DELETE')
... OPTIONS = 'OPTIONS', _('OPTIONS')
... TRACE = 'TRACE', _('TRACE')
... CONNECT = 'CONNECT', _('CONNECT')
...
...
... class Stage(models.TextChoices):
... PRODUCTION = 'production', _('Production')
... TEST = 'test', _('Test')
...
...
... class Source(models.TextChoices):
... FRONTEND_APIv1 = 'frontend-api-v1', _('Frontend API v1')
... FRONTEND_APIv2 = 'frontend-api-v2', _('Frontend API v2')
... FRONTEND_APIv3 = 'frontend-api-v3', _('Frontend API v3')
... MOBILE_APIv3 = 'mobile-api-v3', _('Mobile API v3')
...
...
... class HttpLogger(models.Model):
... added = models.DateTimeField(verbose_name=_('Datetime'), auto_now_add=True)
... modified = models.DateTimeField(verbose_name=_('Datetime'), auto_now=True, db_index=True)
... uuid = models.UUIDField(verbose_name=_('Request ID'), null=False, blank=False, default=uuid4, editable=False)
...
... # Request
... request_ip = models.GenericIPAddressField(verbose_name=_('Request IP'), null=True, blank=True, default=None)
... request_method = models.CharField(verbose_name=_('Request Method'), max_length=10, choices=HttpMethod.choices, default=HttpMethod.POST)
... request_path = models.CharField(verbose_name=_('Request Path'), max_length=255, null=True, blank=True, default=None)
... request_headers = models.TextField(verbose_name=_('Request Headers'), null=True, blank=True, default=None)
... request_cookies = models.TextField(verbose_name=_('Request Cookies'), null=True,blank=True, default=None)
... request_content_type = models.CharField(verbose_name=_('Request Content Type'), max_length=255, null=True, blank=True, default=None)
... request_content_hash = models.CharField(verbose_name=_('Request Content Hash'), max_length=40, db_index=True, null=True, blank=True, default=None)
... request_content = models.TextField(verbose_name=_('Request Content'), null=True, blank=True)
...
... # Response
... response_status = models.PositiveSmallIntegerField(verbose_name=_('Response Status Code'), null=True, blank=True, default=None)
... response_reason = models.CharField(verbose_name=_('Response Reason'),max_length=30, null=True, blank=True,default=None)
... response_headers = models.TextField(verbose_name=_('Response Headers'), null=True,blank=True, default=None)
... response_cookies = models.TextField(verbose_name=_('Response Cookies'), null=True,blank=True, default=None)
... response_content_type = models.CharField(verbose_name=_('Response Content Type'), max_length=255, null=True,blank=True, default=None)
... response_content = models.TextField(verbose_name=_('Response Content'), null=True,blank=True, default=None)
...
... @classmethod
... def add(cls, request: HttpRequest, response: HttpResponse):
... return cls.objects.create(
... request_ip=get_client_ip(request),
... request_method=request.method,
... request_path=request.path,
... request_headers=request.headers,
... request_cookies=request.COOKIES,
... request_content_type=request.content_type,
... request_content_hash=calculate_content_hash(request),
... request_content=request.body.decode('utf-8'),
... response_status=response.status_code,
... response_reason=response.reason_phrase,
... response_headers=response.headers,
... response_cookies=response.cookies,
... response_content_type=response.headers['Content-Type'],
... response_content=response.content.decode('utf-8'))
...
... def __str__(self):
... return f'[{self.uuid}{self.added}, {self.request_ip}] {self.request_method} {self.request_path}'
...
... class Meta:
... verbose_name = _('Http Log')
... verbose_name_plural = _('Http Logs')