Подтвердить что ты не робот

Django logging задает контекст глобально за запрос?

Предположим, что я хочу записать эту строку форматирования:

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

Это можно сделать с помощью этого типа ведения журнала:

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

Это добавит текущий идентификатор пользователя для регистрации сообщений для текущего запроса.

Но дополнительный дидж должен быть добавлен к каждому вызову журнала.

Есть ли хороший способ добавить этот контекст в общую функцию в django (например, Middleware или функцию индекса представления), так что добавлен дополнительный словарь с идентификатором пользователя и все дальнейшие вызовы журналов в текущем запросе также зарегистрируйте текущего пользователя.

4b9b3361

Ответ 1

Существует промежуточное ПО ThreadLocal на https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py, которое поможет вам решить вашу проблему, чтобы сделать текущий запрос доступным во всем мире.

Итак, что вам нужно сделать, это добавить промежуточное ПО в настройку 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

Ответ 2

Здесь возможен подход без локалей потоков или промежуточного программного обеспечения: в вашем views.py, скажем, есть потоки отображения диктов для запросов и блокировка для сериализации доступа к нему:

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

С помощью этой настройки вы должны обнаружить, что в вашем журнале содержится соответствующая информация о запросе.

Ответ 3

Я думаю, что вы ищете настраиваемый формат журнала. В сочетании с ответом mawimawi, чтобы включить информацию о потоке, ваш метод форматирования может автоматически принимать информацию и добавлять ее к каждому зарегистрированному сообщению.

Есть несколько вещей, о которых нужно подумать: во-первых, переменные threadlocal могут быть опасными и, что еще хуже, информацией об утечке, если вы развертываете таким образом, что использует threadpool. Во-вторых, вам нужно быть осторожным, как вы пишете свой форматировщик, если он вызывается в контексте, который не имеет информации о потоке.