我有这个中间件
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
问题是process_response方法中的请求没有.POST,也没有.DATA和.body。我正在使用django-rest-framework,我的请求有Content-Type:application / json
注意,如果我将日志记录放入process_request方法 - 它有.body和我需要的一切。但是,我需要在一个日志条目中同时提供请求和响应。
答案 0 :(得分:10)
这是我制作的完整解决方案
"""
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
注意,这个
'tags': {
'url': request.build_absolute_uri()
}
将允许您在哨兵中按网址过滤。
答案 1 :(得分:5)
Andrey的解决方案将在并发请求中中断。您需要将主体存储在请求范围内的某个位置,然后在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
答案 2 :(得分:3)
Django中没有易于使用的请求记录包,令人沮丧和惊讶。
所以我自己创造了一个。看看:https://github.com/rhumbixsf/django-request-logging.git
使用日志系统,因此易于配置。这是您使用DEBUG级别获得的:
.sv
答案 3 :(得分:3)
上面的所有答案都有一个潜在的问题 - 大 request.body 传递给服务器。在 Django request.body 是一个属性。 (来自框架)
@property
def body(self):
if not hasattr(self, '_body'):
if self._read_started:
raise RawPostDataException("You cannot access body after reading from request's data stream")
try:
self._body = self.read()
except IOError as e:
six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2])
self._stream = BytesIO(self._body)
return self._body
Django 框架只能在一种情况下直接访问机构。 (来自框架)
elif self.META.get('CONTENT_TYPE', '').startswith('application/x-www-form-urlencoded'):
如您所见,属性正文将整个请求读入内存。因此,您的服务器可能会崩溃。而且,它容易受到DoS攻击。 在这种情况下,我建议使用HttpRequest类的另一种方法。 (来自框架)
def readlines(self):
return list(iter(self))
所以,你不再需要这样做了
def process_request(self, request):
request._body_to_log = request.body
你可以这样做:
def process_response(self, request, response):
msg = "method=%s path=%s status=%s request.body=%s response.body=%s"
args = (request.method,
request.path,
response.status_code,
request.readlines(),
response.content)
request_logger.info(msg, *args)
return response
编辑:这种带有request.readlines()的方法存在问题。有时它不会记录任何内容。
答案 4 :(得分:1)
就像访问表单数据以创建新表单一样。
您必须使用request.POST
(也许request.FILES
也是您要记录的内容。)
class LoggingMiddleware(object):
def process_response(self, request, response):
request_logger.log(logging.DEBUG,
"GET: {}. POST: {} response code: {}. response "
"content: {}".format(request.GET, request.POST,
response.status_code,
response.content))
return response
请参阅Here了解请求属性。
答案 5 :(得分:0)
另请注意,response.content
返回bytestring而不是unicode字符串,因此如果需要打印unicode,则需要调用response.content.decode("utf-8")
。
答案 6 :(得分:0)
您不能在中间件的request.POST
部分访问request.body
(或等效地process_response
)。这是ticket提出的问题。尽管您可以在process_request
部分中使用它。前面的答案给出了一个基于类的中间件。 Django 2.0+和3.0+允许基于函数的中间件。
from .models import RequestData # Model that stores all the request data
def requestMiddleware(get_response):
# One-time configuration and initialization.
def middleware(request):
# Code to be executed for each request before
# the view (and later middleware) are called.
try : metadata = request.META ;
except : metadata = 'no data'
try : data = request.body ;
except : data = 'no data'
try : u = str(request.user)
except : u = 'nouser'
response = get_response(request)
w = RequestData.objects.create(userdata=u, metadata=metadata,data=data )
w.save()
return response
return middleware
模型RequestData
如下-
class RequestData(models.Model):
time = models.DateTimeField(auto_now_add=True)
userdata = models.CharField(max_length=10000, default=' ')
data = models.CharField(max_length=20000, default=' ')
metadata = models.CharField(max_length=20000, default=' ')