34
I made a generic RequestLogMiddleware
that can be hooked into any Django View
using decorator_from_middleware
.
request_log/middleware.py
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
request_log/mixins.py
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
my_django_rest_api/views.py
from rest_framework import generics
from ...request_log.mixins import RequestLogViewMixin
class SomeListView(
RequestLogViewMixin,
generics.ListAPIView
):
...
13
Override the APIView.initial()
method to add logging yourself.
Dispatch methods
The following methods are called directly by the viewβs .dispatch() method. These perform any actions that need to occur before or after calling the handler methods such as .get(), .post(), put(), patch() and .delete().
.initial(self, request, *args, **kwargs)
Performs any actions that need to occur before the handler method gets called. This method is used to enforce permissions and throttling, and perform content negotiation.
- [Django]-When to use Django get_absolute_url() method?
- [Django]-Django: is there a way to count SQL queries from an unit test?
- [Django]-Can I have a Django model that has a foreign key reference to itself?
5
Here my current solution to get every REQUEST/RESPONSE in the log. I created a middleware compatible with the old middleware (Django < 1.10) and the new middleware that log every request/response. This solution is the best I found so far.
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
- [Django]-Django staticfiles not found on Heroku (with whitenoise)
- [Django]-How to expire session due to inactivity in Django?
- [Django]-How to override and extend basic Django admin templates?
5
A few years later and Rhumbix has come out with this library, has anyone tried it?
https://github.com/Rhumbix/django-request-logging
MIDDLEWARE = (
...,
'request_logging.middleware.LoggingMiddleware',
...,
)
And configure logging in your app:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.request': {
'handlers': ['console'],
'level': 'DEBUG', # change debug level as appropiate
'propagate': False,
},
},
}
- [Django]-What's the point of Django's collectstatic?
- [Django]-Django's forms.Form vs forms.ModelForm
- [Django]-Django: Safely Remove Old Migrations?
5
Made a custom middleware:
import logging
import time
logger = logging.getLogger(__name__)
class APILogMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start_time = time.time()
response = self.get_response(request)
duration = time.time() - start_time
response_ms = duration * 1000
user = str(getattr(request, 'user', ''))
method = str(getattr(request, 'method', '')).upper()
status_code = str(getattr(response, 'status_code', ''))
request_path = str(getattr(request, 'path', ''))
if status_code == '200' and response_ms > 2000:
logger.info({
"message": "*****SLOW RESPONSE****",
"path": request_path,
"response_time": str(response_ms) + " ms",
"method": method,
"user": user,
"status_code": status_code
})
return response
This logs all APIs which takes greater than 2 seconds to return response.
Just add the full path to MIDDLEWARE = ["path.to.APILogMiddleware"] in your settings.py
- [Django]-Why don't my south migrations work?
- [Django]-Django migration strategy for renaming a model and relationship fields
- [Django]-How to access request body when using Django Rest Framework and avoid getting RawPostDataException
3
Here is the code from @Glyn Jacksonβs Answer:
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 the View:
class ViewClass(RequestLogMiddleware, generics.RetrieveAPIView):
...
- [Django]-How can I handle Exceptions raised by dango-social-auth?
- [Django]-How to limit the maximum value of a numeric field in a Django model?
- [Django]-Django BooleanField as radio buttons?
3
In new Django 2+ better to use Middleware as a callable object like this, just connect it with your project in your Middlewares section of the settings.py file (also Middleware can be a function, not only a class because itβs a callable object old MiddlewareMixin now in the deprecated module of Django):
More info in docs:
https://docs.djangoproject.com/en/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
- [Django]-What are the best practices to use AngularJS with Django
- [Django]-How do I pass template context information when using HttpResponseRedirect in Django?
- [Django]-"Failed building wheel for psycopg2" β MacOSX using virtualenv and pip
2
I found for me that the best and most flexible way was to add logging via a decorator. I simply add the decorator to each of the functions (post, get) that I want to log the request from, as opposed to it being a part of the overal view class. More control over what gets logged. These decorator take the request object passed in (arg[1]) and then logs parts of the request object to a file.
See https://github.com/slogan621/tscharts/commit/39ed479b04b7077f128774d3a203a86d6f68f03e for what amounts to a template for doing this (commit shows changes to settings.py needed to thread the logging into the file logging scheme I have in place, as well as the decorator and example usage).
- [Django]-Django Programming error column does not exist even after running migrations
- [Django]-How can I chain Django's "in" and "iexact" queryset field lookups?
- [Django]-Django template tag to truncate text
0
One option is to use django-requestlogs (https://github.com/Raekkeri/django-requestlogs (Iβm the author)). By default it collects request and response data, (among other basic info) and is easy to hook into the Djangoβs logging system.
- [Django]-Django: Reverse for 'detail' with arguments '('',)' and keyword arguments '{}' not found
- [Django]-How can I upgrade specific packages using pip and a requirements file?
- [Django]-Foreign key from one app into another in Django
0
There is a package already made by jazzband called django-auditlog.
All you have to do is install the package:
pip install django-auditlog
Add the application to your INSTALLED_APPS:
INSTALLED_APPS = [
...
'auditlog',
...
]
And run migration:
manage.py migrate
- If you want automatic logging (Works with DRF), you could:
Add AuditlogMiddleware in your middleware settings
MIDDLEWARE = [
...,
'auditlog.middleware.AuditlogMiddleware',
...
]
Registering your model for logging
from auditlog.registry import auditlog
from django.db import models
class MyModel(models.Model):
pass
# Model definition goes here
auditlog.register(MyModel)
- Or by using manual logging
The docs has not been updated for working with DRF but issues like this suggests that It could be implemented. Tested with my own project.
- [Django]-Factory-boy create a list of SubFactory for a Factory
- [Django]-How to exempt CSRF Protection on direct_to_template
- [Django]-How to specify the login_required redirect url in django?