I have an API built using Django framework . I have to log the following datapoints for each time a request hits the API.
I tried using the request_finished
signal but it does not bring the response object with it. How can I accomplish this?
This is a job for Django Middleware: https://docs.djangoproject.com/en/4.0/topics/http/middleware/
When you install "a middleware" you get opportunities to intervene before, during and after request processing, for all requests.
As described in the documentation link, you need to create a Middleware class and then reference it in your MIDDLEWARE
list in the settings
.
The class based Middleware is simple enough, but more flexible (easily holds state and has it's own methods). Something like this:
class LogRequestsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.perf_counter()
response = self.get_response(request)
end = time.perf_counter()
self.log(request, start, end)
return response
def log(self, request, start, end):
# log request.method, request.path_info, etc.
# log end - start for duration
There are other hooks in this setup but you shouldn't need them. Even if there's an uncaught exception, Django will process it and still return a response object (from get_response
) for you to read.
Bear in mind this is not the same request object you get in a view. It's an instance of django.core.handlers.wsgi.WSGIRequest
, but those values you are looking for should all be there.
To calculate latency you can take values from time.perf_counter()
both before and after the request is processed in your __call__
method, and the difference is the duration:
elapsed = time.perf_counter() # Includes time elapsed during sleep system-wide
duration = time.process_time() # Process time not including sleep