43

出于调试目的,我想使用 Django 的日志记录机制来记录每个传入的请求,当它“到达”django-rest-framework 的门口时。

Djagno 通过以下方式(来自 settings.py 中的 LOGGING 部分)提供其请求的日志记录(仅“警告”日志级别及以上):

'django.request': {
        'handlers': ['mail_admins'],
        'level': 'ERROR',
        'propagate': False,
 },

我希望实现这样的目标(注意:日志级别为 DEBUG):

'rest_framework.request': {
        'handlers': ['logfile'],
        'level': 'DEBUG',
        'propagate': False,
 },

有没有办法在将记录器嵌入到 DRF 的源代码中的情况下做到这一点?
我不知道的 DRF 中是否有某种“日志记录后端”选项?

4

9 回答 9

33

我制作了一个通用RequestLogMiddleware的,可以View使用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
):
    ...
于 2015-01-13T17:51:31.597 回答
13

重写APIView.initial()方法以自己添加日志记录。

调度方法

以下方法由视图的 .dispatch() 方法直接调用。它们执行在调用处理程序方法之前或之后需要发生的任何操作,例如 .get()、.post()、put()、patch() 和 .delete()。

.initial(self, request, *args, **kwargs)
在调用处理程序方法之前执行需要发生的任何操作。此方法用于强制执行权限和限制,以及执行内容协商。

于 2013-03-22T20:19:42.060 回答
6

制作了一个自定义中间件:

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

这会记录所有需要超过 2 秒才能返回响应的 API。只需在 settings.py 中添加 MIDDLEWARE = ["path.to.APILogMiddleware"] 的完整路径

于 2020-06-26T10:26:00.657 回答
4

这是我目前在日志中获取每个请求/响应的解决方案。我创建了一个与旧中间件(Django < 1.10)和记录每个请求/响应的新中间件兼容的中间件。这个解决方案是我迄今为止发现的最好的。

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
于 2018-07-27T01:57:10.197 回答
4

几年后,Rhumbix 推出了这个库,有人试过吗?

https://github.com/Rhumbix/django-request-logging

MIDDLEWARE = (
...,
'request_logging.middleware.LoggingMiddleware',
...,
)

并在您的应用程序中配置日志记录:

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,
        },
    },
}
于 2020-02-11T19:32:08.353 回答
3

在新的 Django 2+中,最好将中间件用作这样的可调用对象,只需在 settings.py 文件的中间件部分将它与您的项目连接起来(中间件也可以是一个函数,而不仅仅是一个类,因为它是一个旧的可调用对象MiddlewareMixin现在在Django的弃用模块中):

文档中的更多信息:
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
于 2019-06-19T09:59:19.183 回答
3

这是来自@Glyn Jackson 的答案的代码:

在中间件/mixin.py

class RequestLogMiddleware(object):

    def initial(self, request, *args, **kwargs):
         super(RequestLogMiddleware, self).initial(request, *args, **kwargs)
         # store/log the request

在视图中:

class ViewClass(RequestLogMiddleware, generics.RetrieveAPIView):
     ...
于 2018-09-18T13:21:33.273 回答
2

我发现最好和最灵活的方法是通过装饰器添加日志记录。我只是将装饰器添加到我想要记录请求的每个函数(post、get)中,而不是作为整体视图类的一部分。更好地控制记录的内容。这些装饰器获取传入的请求对象 (arg[1]),然后将请求对象的部分记录到文件中。

有关执行此操作的模板,请参阅https://github.com/slogan621/tscharts/commit/39ed479b04b7077f128774d3a203a86d6f68f03e(提交显示了对 settings.py 的更改,以将日志记录线程化到我现有的文件日志记录方案中,以及作为装饰器和示例用法)。

于 2018-06-02T21:38:43.217 回答
0

一种选择是使用 django-requestlogs ( https://github.com/Raekkeri/django-requestlogs (我是作者))。默认情况下,它收集请求和响应数据(以及其他基本信息)并且很容易连接到 Django 的日志系统。

于 2021-03-16T13:09:40.223 回答