Django错误日志记录:添加请求头、请求体和用户信息

11
寻找一种方法在我的 views.py 中记录错误日志时,添加标题、正文和用户的电子邮件地址以及异常堆栈跟踪。在搜索了数小时后,许多人建议编写自己的中间件,有些人建议将这种信息记录到单独的日志中。然而,知道代码出错的位置只解决了问题的一部分,在异常期间识别哪个可怜的灵魂受到影响以及发送了什么请求数据可以在纠正问题方面起到很大作用。将这些信息记录在同一个日志文件中对我来说是很合理的。目前,在我的 views.py 中,我有这个简单的设置:
from django.db.models import Min, Max, Q, F, Count, Sum
from django.db import connection
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
from myapp.models import *
import logging

logging.basicConfig(filename="errors.log",
                    level=logging.ERROR,
                    format='%(asctime)s: %(message)s')


def random_view(request):
    if request.user.is_authenticated() and request.user.is_active:
         # generic view code goes here.
    else:
        return HttpResponse(status=401)

这个设置一段时间内运作良好。每次发生异常时,都会记录下时间、异常错误消息和堆栈跟踪。

我如何在堆栈跟踪中添加request.META、request.user.id和request.body?

有什么建议可以帮助我吗?如果能提供解决方案就更好了!

谢谢


你尝试过使用https://dev59.com/KZPfa4cB1Zd3GeqPGKgp吗? - Arpit Solanki
我认为你应该研究现有的解决方案,比如Sentry https://stackoverflow.com/a/44688358/3627387 - Sardorbek Imomaliev
2个回答

11
我认为解决您所面临的记录问题的完整方案是实现一个中间件。该中间件可以与您拥有的任何类型的视图实现配合使用,无论是基于类的视图、基于函数的视图还是 DRF 中的 APIView。
您可以为全面记录定义一个中间件。请确保将中间件放置在身份验证中间件之后。
MIDDLEWARE = [
    ...,
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...,
    'path.to.your.middleware.LogMiddleware'
]

在日志中间件中,您将可以访问请求和响应。您可以通过记录器存储请求、用户(如果已经身份验证)以及来自请求的所有META属性,或者甚至可以将其存储在数据库中。但是请注意,将其存储在数据库中会带来一些成本。您可以通过查看Django中间件文档来了解如何编写中间件。
import traceback

class LogMiddleware():
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        try:
            return self.get_response(request)
        except:
            if request.user.is_authenticated():
                # Log the user
            path = request.get_full_path() # Get the URL Path
            tb = traceback.format_exc() # Get the traceback
            meta = request.META # Get request meta information
            # Log everything
            raise  # Raise exception again after catching

你可以从HttpRequest的Django文档中阅读有关所有元属性的信息。如果需要任何澄清,请告诉我。

如果你想将日志存储到数据库,并构建一个基于时间戳进行过滤的分析仪表板,你会选择哪个数据库? - undefined

2
我会在这里使用装饰器。直接进入代码...
import logging
from functools import wraps
from django.http import HttpResponse, HttpRequest

logging.basicConfig(filename="errors.log",
                    level=logging.ERROR,
                    format='%(asctime)s: %(message)s')
log = logging.getLogger(__name__)

def log_exceptions(wrapped):
    @wraps(wrapped)
    def wrapper(*args, **kwargs):
        try:
            return wrapped(*args, **kwargs)
        except:
            # log and re-raise
            request = args[0] if len(args) > 0 and isinstance(args[0], HttpRequest) else None
            msg = ("\nuser.id/email: {}/{}\nMETA: {}...\nbody: {}"
                   .format(request.user.id,
                           getattr(request.user, 'email','?'),
                           str(request.META)[:80],
                           request.body)
                   if request
                   else "not a HttpRequest")
            log.exception(msg)
            raise
    return wrapper

@log_exceptions
def random_view(request):
    raise ValueError("simulate a crash")
    if request.user.is_authenticated() and request.user.is_active:
        return HttpResponse('hi')
         # generic view code goes here.
    else:
        return HttpResponse(status=401)

"并且 errors.log 应该捕获类似以下的内容"
2017-06-27 20:48:09,282: 
user.id/email: 1/test@domain.com
META: {'SESSION_MANAGER': 'local/acb:@/tmp/.ICE-unix/4255,unix/acb:/tmp/.ICE-unix/4255...
body: b''
Traceback (most recent call last):
  File "/home/rod/pyves/rangetest/rangetest/data/views.py", line 14, in wrapper
    return wrapped(*args, **kwargs)
  File "/home/rod/pyves/rangetest/rangetest/data/views.py", line 31, in random_view
    raise ValueError("simulate a crash")
ValueError: simulate a crash

请注意,您可能还会在错误日志中看到Django崩溃日志。您可以使用Django的文档完善但仍然复杂的日志配置将日志拆分为单独的文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接