django日志记录根据请求全局设置上下文?

时间:2013-04-25 08:38:39

标签: python django logging

假设我想像这样的格式化字符串一样记录:

%(levelname)s %(asctime)s %(module)s %(funcName)s %(message)s %(user_id)

可以使用这种类型的日志记录命令来完成:

logging.error('Error fetching information', extra = { 'user_id': 22 } )

这会将当前用户ID添加到当前请求的日志消息中。

但是额外的dict需要添加到每个日志记录调用中。

是否有一种很好的方法可以在django中的公共函数中添加此上下文(例如,中间件或视图的索引函数),以便设置具有用户ID的额外字典,并在当前请求中进行所有进一步的日志记录调用还记录当前用户。

3 个答案:

答案 0 :(得分:8)

https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py上存在一个ThreadLocal中间件,可以帮助您解决当前请求在任何地方都可用的问题。

所以你需要做的是将中间件添加到MIDDLEWARE_CLASSES设置中,并在这样的地方创建一个函数:

 from django_tools.middlewares import ThreadLocal
 def log_something(levelname, module, funcname, message):
     user = ThreadLocal.get_current_user()
     # do your logging here. "user" is the user object and the user id is in user.pk

答案 1 :(得分:2)

这是一种没有线程本地或中间件的可能方法:在views.py中,比如说,有一个dict映射线程到请求,以及一个锁定序列化对它的访问:

from threading import RLock
shared_data_lock = RLock()
request_map = {}

def set_request(request):
    with shared_data_lock:
        request_map[threading.current_thread()] = request

创建以下过滤器并附加到需要输出特定于请求的信息的处理程序:

import logging
class RequestFilter(logging.Filter):
    def filter(self, record):
        with shared_data_lock:
            request = request_map.get(threading.current_thread())
        if request:
            # Set data from the request into the record, e.g.
            record.user_id = request.user.id
        return True

然后,作为每个视图的第一个语句,在地图中设置请求:

def my_view(request, ...):
    set_request(request)
    # do your other view stuff here

使用此设置,您会发现您的日志输出包含相关的特定于请求的信息。

答案 2 :(得分:1)

我认为您正在寻找custom log formatter。结合mawimawi的回答来包含threadlocal信息,您的格式化方法可以自动获取信息并将其添加到每条记录的消息中。

有几点需要考虑:首先,如果以使用线程池的方式进行部署,则threadlocal变量可能是危险的,更糟糕​​的是泄漏信息。其次,如果在没有threadlocal信息的上下文中调用格式化程序,你需要谨慎编写格式化程序。