2016-08-08 51 views
0

Hier ist ein einfacher Python-Filter, der nur "TEST -" vor eine Protokollnachricht stellt. (Der eigentliche Filter wird nicht hilfreiche Verarbeitung später):Warum wird mein Protokollierungsfilter auf den falschen Handler angewendet?

class TimeStamp_Filter(logging.Filter): 
    def filter(self, record): 
     record.msg = "TEST - " + str(record.msg) 
     return True 

Und hier ist die config in einer JSON-Datei und analysierte mit dictConfig() gezogen:

{ 
    "version": 1, 
    "disable_existing_loggers": false, 
    "filters": { 
     "timestamp_filter": { 
      "()": "TimeStamp_Filter" 
     } 
    }, 
    "handlers": { 
     "file_handler": { 
      "class": "logging.FileHandler", 
      "level": "INFO", 
      "filename": "../log/default.log", 
      "mode": "a"      
     }, 
     "console": { 
      "class": "logging.StreamHandler", 
      "level": "DEBUG", 
      "filters": ["timestamp_filter"], 
      "stream": "ext://sys.stdout" 
     } 
    }, 
    "root": { 
     "level": "DEBUG", 
     "handlers": ["console", "file_handler"] 
    } 
} 

Der Filter selbst scheint zu funktionieren - wenn Ich erstelle einen Logger und logger.info("Hello, world!") laufen, bekomme ich die Ausgabe TEST - Hello, world! auf dem Bildschirm.

Aber ich auch bekomme diese Ausgabe (einschließlich der "TEST") in meiner default.log Datei. Ich hatte gedacht, dass, indem ich die timestamp_filter nur an die console Handler anbrachte, würde ich diese TEST-Ausgabe nur auf dem Bildschirm bekommen.

Warum wird auch an den Handler file_handler gesendet und endet in meiner Protokolldatei?

Antwort

0

Sie ändern die Nachricht des Protokolldatensatzes von einem Filter. Das verursacht das Problem.

Python wird diesen Filter auf Ihre Konsolenausgabe in Ordnung anwenden, aber wenn dies der Fall ist, wird die ursprüngliche Protokollnachricht geändert. Wenn die Protokollnachricht an den Dateihandler übergeben wird, hat sich die Nachricht bereits geändert und enthält diese zusätzliche Eingabe.

Wenn Sie das Protokollformat für bestimmte Handler ändern möchten, sollten Sie stattdessen Formatierer verwenden. Filterung dient zur Auswahl, welche Nachricht protokolliert wird und welche nicht.

Update: Wie in den Kommentaren ist hier ein Beispielcode, der erläutert, wie wir benutzerdefinierte Formatierer verwenden und Geschäftslogik darin verarbeiten können.

import logging 
import sys 


class CustomFormatter(logging.Formatter): 
    def format(self, record): 
     mycondition = True # Here goes your business logic 
     formatted_message = super().format(record=record) 

     if mycondition: 
      formatted_message += "TEST" 

     return formatted_message 


logger = logging.getLogger("test") 
logger.setLevel(logging.DEBUG) 

handler = logging.StreamHandler(stream=sys.stdout) 
handler.setFormatter(CustomFormatter()) 
logger.addHandler(handler) 



logger.info("Hello!") 
+0

Masnum, danke für die Erklärung. Ich habe meine Idee auf dem Python Cookbook (https://docs.python.org/3/howto/logging-cookbook.html#using-filters-to-impart-contextual-information) basiert, wo sie vorschlagen, einen Filter zu verwenden, um zu injizieren zusätzliche Informationen in die Nachricht, wie IP-Daten. In meinem Fall erfordern die Daten, die injiziert werden müssen, eine gewisse Geschäftslogik. Ist es möglich, Python-Code zu einem Formatierer hinzuzufügen? Die einzigen Beispiele, die ich gesehen habe, beinhalten das Ändern der Ausgabezeichenfolge unter Verwendung vordefinierter Variablen wie '% (asctime) s''% (processName) ', usw. - nichts, was einen Block von Code betrifft. –

+0

Ja, Sie können die Geschäftslogik auch in Formatierer einfügen. Aber denken Sie daran, das Hauptdatensatzobjekt nicht zu ändern. Das würde ähnliche Probleme verursachen. – masnun

+0

Masnun, nochmals vielen Dank für Ihre Hilfe. Könnten Sie mir ein Beispiel dafür geben, wie diese Geschäftslogik in einen Formatierer einfließen kann? Ich weiß, wie man es mit einem Formatierungsstring mit vordefinierten Variablen setzt (zB 'formatter = logging.Formatter ('TEST -% (asctime) s -% (name) s -% (levelname) s -% (message) s') ') Aber ich gestehe, dass ich nicht verstehe, wie man den ganzen Formatierer in eine Funktion oder Klasse bringt, um komplexere Logik anzuwenden. (um nur ein Beispiel zu geben, das Wort "TEST" nur zu drucken, wenn der "socket.hostname()" einen bestimmten Wert hat). –