如何在 Django 中的自定义日志格式化程序中访问请求对象?

问题描述 投票:0回答:1

我设置了一个自定义格式化程序,将我的数据以 JSON 格式记录到文本文件中:

class CustomJsonFormatter(jsonlogger.JsonFormatter):
    def add_fields(self, log_record, record, message_dict):
      super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
      log_record['timestamp'] = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')
      log_record['level'] = record.levelname
      log_record['location'] = record.name

我希望能够自动访问这种格式的请求对象,因为我有一个“唯一的请求标识符”,我想将其添加到我的日志中。这样我就知道哪些日志行属于哪个请求。

class CustomJsonFormatter(jsonlogger.JsonFormatter):
    def add_fields(self, log_record, record, message_dict):
      super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
      log_record['timestamp'] = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')
      log_record['level'] = record.levelname
      log_record['location'] = record.name

      log_record['request_id'] = request.uuid   <--- Something like this

有没有一种方法可以实现此目的,而无需手动将请求对象传递到每个日志行?

提前非常感谢

python django django-rest-framework python-logging
1个回答
1
投票

您可以使用中间件将请求附加到线程上下文,然后通过 threadlocals 在格式化程序中访问它:

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

    def __call__(self, request):
        self.process_request(request)
        response = self.get_response(request)
        self.process_response(request, response)
        return response

    def process_request(self, request):
        Thread.currentThread().request = request

    def process_response(self, request, response):
        if hasattr(Thread.currentThread(), 'request'):
            del Thread.currentThread().request
        return response

然后在你的格式化程序中:

threadlocals.request.uuid

请注意,这使用线程本地存储,因此只有当您的 Django 应用程序使用线程而不是多进程时,这才能正常工作。

或者,您可以将请求作为额外参数显式传递给记录器:

logger.info('message', extra={'request': request})

然后在格式化程序中将其作为 message_dict['request'] 访问。这也将跨进程工作。

© www.soinside.com 2019 - 2024. All rights reserved.