Ich habe ein kleines Python-Projekt mit der folgenden Struktur:
Project
-- pkg01
-- test01.py
-- pkg02
-- test02.py
-- logging.conf
Ich plane, das Standardprotokollierungsmodul zu verwenden, um Nachrichten an stdout und eine Protokolldatei zu drucken. Um das Protokollierungsmodul verwenden zu können, ist eine Initialisierung erforderlich.
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')
logger.info('testing')
Derzeit führe ich diese Initialisierung in jedem Modul durch, bevor ich mit der Protokollierung von Nachrichten beginne. Ist es möglich, diese Initialisierung nur einmal an einem Ort durchzuführen, sodass dieselben Einstellungen durch Protokollierung im gesamten Projekt wiederverwendet werden?
fileConfig
jedes Modul aufrufen , das die Protokollierung durchführt, es sei denn, Sie habenif __name__ == '__main__'
in allen Modulen Logik. Die Antwort von prost ist keine gute Vorgehensweise, wenn es sich bei dem Paket um eine Bibliothek handelt, obwohl dies möglicherweise für Sie funktioniert. Sie sollten die Anmeldung in Bibliothekspaketen nicht konfigurieren, außer eine hinzuzufügenNullHandler
.package/__init__.py
. Dies ist normalerweise nicht der Ort, an dem Sieif __name__ == '__main__'
Code eingeben. Außerdem sieht das Beispiel von prost so aus, als würde es den Konfigurationscode beim Import bedingungslos aufrufen, was für mich nicht richtig aussieht. Im Allgemeinen sollte die Protokollierung des Konfigurationscodes an einem Ort erfolgen und nicht als Nebeneffekt des Imports auftreten, außer wenn Sie __main__ importieren.if __name__ == '__main__'
? (es wird nicht explizit in Frage gestellt, ob dies der Fall ist)Antworten:
Es wird empfohlen, in jedem Modul einen Logger wie folgt zu definieren:
in der Nähe der Oberseite des Moduls und dann in anderem Code im Modul tun Sie z
Wenn Sie die Protokollierungsaktivität innerhalb eines Moduls unterteilen müssen, verwenden Sie z
und melden Sie sich bei
loggerA
undloggerB
nach Bedarf an.Führen Sie in Ihrem Hauptprogramm oder Ihren Hauptprogrammen z.
oder
Siehe hier für aus mehreren Modulen Anmeldung und hier für die Protokollierung Konfiguration für Code, der durch einen anderen Code als Bibliothek - Modul verwendet wird.
Update: Beim Aufrufen
fileConfig()
möchten Sie möglicherweise angeben,disable_existing_loggers=False
ob Sie Python 2.6 oder höher verwenden ( weitere Informationen finden Sie in den Dokumenten ). Der Standardwert ist dieTrue
Abwärtskompatibilität. Dadurch werden alle vorhandenen Protokollierer deaktiviert, esfileConfig()
sei denn, sie oder ihre Vorfahren werden in der Konfiguration explizit benannt. Wenn der Wert auf gesetzt istFalse
, werden vorhandene Logger in Ruhe gelassen. Wenn Sie Python 2.7 / Python 3.2 oder höher verwenden, sollten Sie diedictConfig()
API in Betracht ziehen, die besser ist als die besserefileConfig()
Kontrolle über die Konfiguration.quelle
disable_existing_loggers
Flag, dasTrue
standardmäßig aktiviert ist, aber auf gesetzt werden kannFalse
.Tatsächlich ist jeder Logger ein untergeordnetes Element des Paketloggers des Elternteils (dh
package.subpackage.module
erbt die Konfiguration vonpackage.subpackage)
. Sie müssen also nur den Root-Logger konfigurieren. Dies kann erreicht werden durchlogging.config.fileConfig
(Ihre eigene Konfiguration für Logger) oderlogging.basicConfig
(legt den Root-Logger fest). . Setup - Protokollierung im Eingabemodul (__main__.py
oder was auch immer Sie zum Beispiel ausführen willmain_script.py
.__init__.py
funktioniert auch)using basicConfig:
using fileConfig:
und erstellen Sie dann jeden Logger mit:
Weitere Informationen finden Sie im Advanced Logging Tutorial .
quelle
__main__.py
(z. B. wenn ich das Modul in einem Skript verwenden möchte, das keinen Logger hat), wirdlogging.getLogger(__name__)
immer noch eine Art Logging im Modul durchgeführt oder wird eine Ausnahme ausgelöst?Ich mache es immer wie unten.
Verwenden Sie eine einzelne Python-Datei, um mein Protokoll als Singleton-Muster mit dem Namen '
log_conf.py
' zu konfigurieren.Importieren Sie in einem anderen Modul einfach die Konfiguration.
Dies ist ein Singleton-Muster, das einfach und effizient protokolliert werden kann.
quelle
Einige dieser Antworten deuten darauf hin, dass Sie sich oben in einem Modul befinden
Nach meinem Verständnis wird dies als sehr schlechte Praxis angesehen . Der Grund dafür ist, dass die Dateikonfiguration standardmäßig alle vorhandenen Protokollierer deaktiviert. Z.B
Und in Ihrem Hauptmodul:
Jetzt ist das in logging.ini angegebene Protokoll leer, da der vorhandene Protokollierer durch den Aufruf von fileconfig deaktiviert wurde.
Es ist zwar möglich, dies zu umgehen (disable_existing_Loggers = False), aber realistischerweise wissen viele Clients Ihrer Bibliothek nichts über dieses Verhalten und erhalten Ihre Protokolle nicht. Machen Sie es Ihren Kunden einfach, indem Sie logging.getLogger immer lokal aufrufen. Hut Tipp: Ich habe von diesem Verhalten auf der Website von Victor Lin erfahren .
Es empfiehlt sich daher, logging.getLogger immer lokal aufzurufen. Z.B
Wenn Sie in Ihrer Hauptdatei fileconfig verwenden, setzen Sie disable_existing_loggers = False, nur für den Fall, dass Ihre Bibliotheksdesigner Logger-Instanzen auf Modulebene verwenden.
quelle
logging.config.fileConfig('logging.ini')
vorher nicht rennenimport my_module
? Wie in dieser Antwort vorgeschlagen .logger = logging.getLogger(__name__)
"Eine einfache Möglichkeit, eine Instanz der Protokollierungsbibliothek in mehreren Modulen zu verwenden, war für mich die folgende Lösung:
base_logger.py
Andere Dateien
quelle
Eine andere Lösung einwerfen.
In der init .py meines Moduls habe ich so etwas wie:
Dann brauche ich in jedem Modul einen Logger:
Wenn die Protokolle fehlen, können Sie ihre Quelle nach dem Modul unterscheiden, von dem sie stammen.
quelle
Sie könnten sich auch so etwas einfallen lassen!
Jetzt können Sie mehrere Logger in demselben Modul und im gesamten Projekt verwenden, wenn das oben Gesagte in einem separaten Modul definiert und in andere Module importiert wird, in denen eine Protokollierung erforderlich ist.
quelle
@ Yarkees Lösung schien besser. Ich möchte noch etwas hinzufügen -
LoggerManager kann also für die gesamte Anwendung steckbar sein. Hoffe, es macht Sinn und Wert.
quelle
Es gibt mehrere Antworten. Am Ende hatte ich eine ähnliche, aber andere Lösung, die für mich Sinn macht. Vielleicht macht sie auch für Sie Sinn. Mein Hauptziel war es, Protokolle nach ihrer Ebene an Handler übergeben zu können (Protokolle auf Debug-Ebene an die Konsole, Warnungen und höher an Dateien):
hat eine nette util-Datei namens logger.py erstellt:
Die flask.app ist ein fest codierter Wert in der Flasche. Der Anwendungslogger beginnt immer mit flask.app als Modulnamen.
Jetzt kann ich es in jedem Modul im folgenden Modus verwenden:
Dadurch wird mit minimalem Aufwand ein neues Protokoll für "app.flask.MODULE_NAME" erstellt.
quelle
Die beste Vorgehensweise wäre, ein Modul separat zu erstellen, das nur eine Methode enthält, deren Aufgabe es ist, der aufrufenden Methode einen Logger-Handler zuzuweisen. Speichern Sie diese Datei als m_logger.py
Rufen Sie jetzt die Methode getlogger () auf, wenn ein Logger-Handler benötigt wird.
quelle
--debug
Option in der App haben und die Protokollierungsstufe in allen Loggern in Ihrer App basierend auf diesem Parameter festlegen möchten ...get_logger(level=logging.INFO)
um eine Art Singleton zurückzugeben. Wenn es also zum ersten Mal von der Haupt-App aufgerufen wird, initialisiert es den Logger und die Handler mit der richtigen Ebene und gibt dann dasselbelogger
Objekt an alle anderen Methoden zurück.Neu in Python, daher weiß ich nicht, ob dies ratsam ist, aber es funktioniert hervorragend, wenn Boilerplate nicht neu geschrieben wird.
Ihr Projekt muss eine init .py haben, damit es als Modul geladen werden kann
sys._getframe(1)
Vorschlag kommt von hierSo verwenden Sie Ihren Logger in einer anderen Datei:
Vorsichtsmaßnahmen:
import [your module]
funktioniert es nicht:python -m [your module name].[your filename without .py]
__main__
, aber bei jeder verwendeten Lösung tritt__name__
dieses Problem auf.quelle