Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I have a middleware where I a want to log every request/response. How can I access to POST data?

Tags:

rest

django

I have this middleware

import logging  request_logger = logging.getLogger('api.request.logger')   class LoggingMiddleware(object):      def process_response(self, request, response):         request_logger.log(logging.DEBUG,                "GET: {}. POST: {} response code: {}. response "                "content: {}".format(request.GET, request.DATA,                                        response.status_code,                                        response.content))         return response 

The problem is that request in process_response method has no .POST nor .DATA nor .body. I am using django-rest-framework and my requests has Content-Type: application/json

Note, that if I put logging to process_request method - it has .body and everything I need. However, I need both request and response in a single log entry.

like image 260
Andrii Zarubin Avatar asked Jul 16 '14 15:07

Andrii Zarubin


People also ask

What is logger Express?

Morgan — HTTP logging middleware for express. It provides the ability to log incoming requests by specifying the formatting of log instance based on different request related information. For example: :method :url :status :response-time ms - :res[content-length]


2 Answers

Here is complete solution I made

""" Api middleware module """ import logging  request_logger = logging.getLogger('api.request.logger')   class LoggingMiddleware(object):     """     Provides full logging of requests and responses     """     _initial_http_body = None      def process_request(self, request):         self._initial_http_body = request.body # this requires because for some reasons there is no way to access request.body in the 'process_response' method.       def process_response(self, request, response):         """         Adding request and response logging         """         if request.path.startswith('/api/') and \                 (request.method == "POST" and                          request.META.get('CONTENT_TYPE') == 'application/json'                  or request.method == "GET"):             request_logger.log(logging.DEBUG,                                "GET: {}. body: {} response code: {}. "                                "response "                                "content: {}"                                .format(request.GET, self._initial_http_body,                                        response.status_code,                                        response.content), extra={                     'tags': {                         'url': request.build_absolute_uri()                     }                 })         return response 

Note, this

'tags': {     'url': request.build_absolute_uri() } 

will allow you to filter by url in sentry.

like image 175
Andrii Zarubin Avatar answered Oct 11 '22 19:10

Andrii Zarubin


Andrey's solution will break on concurrent requests. You'd need to store the body somewhere in the request scope and fetch it in the process_response().

class RequestLoggerMiddleware(object):      def process_request(self, request):         request._body_to_log = request.body      def process_response(self, request, response):         if not hasattr(request, '_body_to_log'):             return response          msg = "method=%s path=%s status=%s request.body=%s response.body=%s"         args = (request.method,                 request.path,                 response.status_code,                 request._body_to_log,                 response.content)          request_logger.info(msg, *args)          return response 
like image 37
siavach Avatar answered Oct 11 '22 21:10

siavach