假设我想像这样的格式化字符串一样记录:
%(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的额外字典,并在当前请求中进行所有进一步的日志记录调用还记录当前用户。
答案 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信息的上下文中调用格式化程序,你需要谨慎编写格式化程序。