Zu Debugging-Zwecken möchte ich den Protokollierungsmechanismus von Django verwenden, um jede eingehende Anforderung zu protokollieren, wenn sie bei Django-Rest-Framework "ankommt".
Djagno bietet die Protokollierung seiner Anforderungen (nur Protokollstufe "Warnung" und höher) auf folgende Weise an (aus dem LOGGING-Abschnitt in settings.py):
'Django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': False,
},
Ich möchte etwas erreichen (Hinweis: Log-Level ist DEBUG):
'rest_framework.request': {
'handlers': ['logfile'],
'level': 'DEBUG',
'propagate': False,
},
Gibt es eine Möglichkeit, dass ich ohne einen Logger in den DRF-Quellcode einbetten kann?
Gibt es in DRF möglicherweise eine "Logging Backend" -Option, von der ich keine Kenntnis habe?
Ich habe ein generisches RequestLogMiddleware
erstellt, das mit decorator_from_middleware
in jedes Django View
eingebunden werden kann.
import socket
import time
class RequestLogMiddleware(object):
def process_request(self, request):
request.start_time = time.time()
def process_response(self, request, response):
if response['content-type'] == 'application/json':
if getattr(response, 'streaming', False):
response_body = '<<<Streaming>>>'
else:
response_body = response.content
else:
response_body = '<<<Not JSON>>>'
log_data = {
'user': request.user.pk,
'remote_address': request.META['REMOTE_ADDR'],
'server_hostname': socket.gethostname(),
'request_method': request.method,
'request_path': request.get_full_path(),
'request_body': request.body,
'response_status': response.status_code,
'response_body': response_body,
'run_time': time.time() - request.start_time,
}
# save log_data in some way
return response
from Django.utils.decorators import decorator_from_middleware
from .middleware import RequestLogMiddleware
class RequestLogViewMixin(object):
"""
Adds RequestLogMiddleware to any Django View by overriding as_view.
"""
@classmethod
def as_view(cls, *args, **kwargs):
view = super(RequestLogViewMixin, cls).as_view(*args, **kwargs)
view = decorator_from_middleware(RequestLogMiddleware)(view)
return view
from rest_framework import generics
from ...request_log.mixins import RequestLogViewMixin
class SomeListView(
RequestLogViewMixin,
generics.ListAPIView
):
...
Überschreiben Sie die Methode APIView.initial()
, um die Protokollierung selbst hinzuzufügen.
Versandmethoden
Die folgenden Methoden werden direkt von der .dispatch () - Methode der Ansicht aufgerufen. Diese führen alle Aktionen aus, die vor oder nach dem Aufruf der Handler-Methoden wie .get (), .post (), put (), patch () und .delete () ausgeführt werden müssen.
.initial(self, request, *args, **kwargs)
Führt alle Aktionen aus, die ausgeführt werden müssen, bevor die Handler-Methode aufgerufen wird. Diese Methode wird zum Erzwingen von Berechtigungen und zur Drosselung und zum Durchführen von Inhaltsverhandlungen verwendet.
Hier ist der Code von @Glyn Jacksons Antwort:
in Middleware/mixin.py
class RequestLogMiddleware(object):
def initial(self, request, *args, **kwargs):
super(RequestLogMiddleware, self).initial(request, *args, **kwargs)
# store/log the request
in der Ansicht:
class ViewClass(RequestLogMiddleware, generics.RetrieveAPIView):
...
Ich fand für mich die beste und flexibelste Möglichkeit, die Protokollierung über einen Dekorateur hinzuzufügen. Ich füge den Decorator einfach zu jeder der Funktionen hinzu (post, get), von denen ich die Anforderung protokollieren möchte, im Gegensatz dazu, dass sie nicht Teil der Gesamtansicht ist. Mehr Kontrolle darüber, was protokolliert wird. Diese Dekorierer nehmen das übergebene Anforderungsobjekt (arg [1]) und protokollieren dann Teile des Anforderungsobjekts in einer Datei.
Siehe https://github.com/slogan621/tscharts/commit/39ed479b04b7077f128774d3a203a86d6f68f03e , um zu erfahren, was eine Vorlage dafür darstellt (das Festschreiben zeigt Änderungen an settings.py an, die für das Threading erforderlich sind Platz sowie den Dekorateur und die Beispielnutzung).
Hier meine aktuelle Lösung, um jede REQUEST/RESPONSE in das Protokoll aufzunehmen. Ich habe eine Middleware erstellt, die mit der alten Middleware (Django <1.10) und der neuen Middleware kompatibel ist, die jede Anfrage/Antwort protokolliert. Diese Lösung ist die beste, die ich bisher gefunden habe.
import logging
from Django.utils.deprecation import MiddlewareMixin
_logger = logging.getLogger(__name__)
class LogRestMiddleware(MiddlewareMixin):
"""Middleware to log every request/response.
Is not triggered when the request/response is managed using the cache
"""
def _log_request(self, request):
"""Log the request"""
user = str(getattr(request, 'user', ''))
method = str(getattr(request, 'method', '')).upper()
request_path = str(getattr(request, 'path', ''))
query_params = str(["%s: %s" %(k,v) for k, v in request.GET.items()])
query_params = query_params if query_params else ''
_logger.debug("req: (%s) [%s] %s %s", user, method, request_path, query_params)
def _log_response(self, request, response):
"""Log the response using values from the request"""
user = str(getattr(request, 'user', ''))
method = str(getattr(request, 'method', '')).upper()
status_code = str(getattr(response, 'status_code', ''))
status_text = str(getattr(response, 'status_text', ''))
request_path = str(getattr(request, 'path', ''))
size = str(len(response.content))
_logger.debug("res: (%s) [%s] %s - %s (%s / %s)", user, method, request_path, status_code, status_text, size)
def process_response(self, request, response):
"""Method call when the middleware is used in the `MIDDLEWARE_CLASSES` option in the settings. Django < 1.10"""
self._log_request(request)
self._log_response(request, response)
return response
def __call__(self, request):
"""Method call when the middleware is used in the `MIDDLEWARE` option in the settings (Django >= 1.10)"""
self._log_request(request)
response = self.get_response(request)
self._log_response(request, response)
return response
In neu Django 2+ besser Middleware als aufrufbares Objekt verwenden, verbinden Sie es einfach mit Ihrem Projekt in Ihrem Middlewares-Abschnitt der settings.py-Datei (Middleware kann auch eine Funktion sein, nicht nur eine Klasse, da es sich um ein aufrufbares Objekt handelt. alt MiddlewareMixin jetzt im veraltet Modul von Django):
Weitere Informationen in der Dokumentation:
https://docs.djangoproject.com/de/2.2/topics/http/middleware/#writing-your-own-middleware
class UserActivityLogMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print(request.method) # In this string we catch request object.
response = self.get_response(request)
return response