2013-04-25 13 views
19

Lets sagen, dass ich wie diese Formatierung Zeichenfolge protokollieren möchten:django Logging Set Kontext global pro Anfrage?

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

Es kann mit dieser Art der Protokollierung Befehl:

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

Dadurch wird der aktuelle Benutzer-ID in den Logging-Nachrichten für aktuelle Anfrage

Das zusätzliche Diktat muss jedoch zu jedem Protokollierungsaufruf hinzugefügt werden.

Gibt es eine gute Möglichkeit, diesen Kontext in einer gemeinsamen Funktion in django (z. B. Middleware oder Indexfunktion einer Sicht) hinzuzufügen, so dass das zusätzliche Wörterbuch mit Benutzer-ID festgelegt ist und alle weiteren Protokollierungsaufrufe in der aktuellen Bitte melden Sie auch den aktuellen Benutzer an.

+1

Warum ist die Antwort von 'mawimawi' nicht akzeptabel? Liegt es an der thread-lokalen Verwendung oder an etwas anderem? –

+0

Vinay Sajip, einige Rep-Punkte werden alleine sterben. So funktioniert es bei stackoverflow. – mawimawi

+0

@VinaySajip, ja, versucht, die Verwendung von Thread-lokalen und einer zusätzlichen Middleware zu vermeiden. Wenn es eine Möglichkeit gibt, die Protokollierungsklasse zu erweitern, wäre das großartig. – DhruvPathak

Antwort

8

Es gibt eine ThreadLocal Middleware auf https://github.com/jedie/django-tools/blob/master/django_tools/middlewares/ThreadLocal.py, die Ihnen bei Ihrem Problem hilft, die aktuelle Anfrage überall verfügbar zu machen.

Also, was Sie tun müssen, ist die Middleware auf Ihre MIDDLEWARE_CLASSES Einstellung hinzufügen und eine Funktion irgendwo wie folgt erstellen: in Ihre views.py, sagen wir,: ohne Gewinde Einheimische oder Middleware

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

Hier ist ein möglicher Ansatz haben ein dict Mapping Threads auf Anfragen, und einen Verriegelungs serialise Zugriff darauf:

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

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

erstellen den folgenden Filter und heften sich an die Behandlungsroutinen, die zur Ausgabe von anforderungsspezifischen Informationen benötigen:

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 

Dann als erste Anweisung jeder Ansicht, die Anfrage in der Karte gesetzt:

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

Mit dieser Einrichtung sollten Sie feststellen, dass Ihre Log-Ausgabe die entsprechenden anforderungsspezifische Informationen enthält.

1

Ich glaube, Sie suchen nach einem custom log formatter. In Verbindung mit der Antwort von mawimawi, um die Threadlocal-Informationen einzubeziehen, könnte Ihre Formatierungsmethode die Informationen automatisch übernehmen und sie jeder protokollierten Nachricht hinzufügen.

Es gibt ein paar Dinge, über die man nachdenken sollte: Erstens, threadlocal-Variablen können gefährlich sein und, schlimmer noch, Informationen verlieren, wenn Sie auf eine Weise bereitstellen, die einen threadpool verwendet. Zweitens müssen Sie vorsichtig sein, wie Sie Ihren Formatierer schreiben, falls er in einem Kontext aufgerufen wird, der nicht die lokalen Threadinformationen enthält.