python - loggers - django logging set context globalmente por solicitud?
loggers django (3)
Digamos que quiero registrar como esta cadena de formato:
%(levelname)s %(asctime)s %(module)s %(funcName)s %(message)s %(user_id)
Se puede hacer usando este tipo de comando de registro:
logging.error(''Error fetching information'', extra = { ''user_id'': 22 } )
Esto agregará el ID de usuario actual al registro de mensajes para la solicitud actual.
Pero el dictado adicional debe agregarse a cada llamada de registro.
¿Existe una buena manera de agregar este contexto en una función común en django (por ejemplo, Middleware, o función de índice de una vista), para que se establezca el diccionario adicional con la identificación del usuario, y todas las llamadas de registro adicionales en la solicitud actual también registren el usuario actual.
Creo que estás buscando un formateador de registro personalizado . Tomado en conjunto con la respuesta de mawimawi para incluir la información de la ubicación del subproceso, su método de formato podría tomar la información automáticamente y agregarla a cada mensaje registrado.
Hay un par de cosas en que pensar: primero, las variables localizadas en subprocesos pueden ser peligrosas y, peor aún, filtrar información si se implementa de una manera que use un conjunto de subprocesos. En segundo lugar, debe tener cuidado al escribir su formateador en caso de que se le llame en un contexto que no tenga la información de threadlocal.
Este es un posible enfoque sin locals o middleware de subprocesos: en su views.py
, digamos, tenga un dictado asignando subprocesos a las solicitudes, y un bloqueo para serializar el acceso a ellos:
from threading import RLock
shared_data_lock = RLock()
request_map = {}
def set_request(request):
with shared_data_lock:
request_map[threading.current_thread()] = request
Cree el siguiente filtro y adjúntelo a los controladores que necesitan generar información específica de la solicitud:
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
Luego, como la primera declaración de cada vista, establezca la solicitud en el mapa:
def my_view(request, ...):
set_request(request)
# do your other view stuff here
Con esta configuración, debería encontrar que la salida de su registro contiene la información relevante específica de la solicitud.
Existe un middleware ThreadLocal en github.com/jedie/django-tools/blob/master/django_tools/… que le ayuda con su problema al hacer que la solicitud actual esté disponible en todas partes.
Entonces, lo que debe hacer es agregar el middleware a su configuración de MIDDLEWARE_CLASSES y crear una función como esta:
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