Python-logging von mehreren threads
Ich habe eine log.py
- Modul, das verwendet wird, in mindestens zwei weiteren Modulen (server.py
und device.py
).
Er hat diese globals:
fileLogger = logging.getLogger()
fileLogger.setLevel(logging.DEBUG)
consoleLogger = logging.getLogger()
consoleLogger.setLevel(logging.DEBUG)
file_logging_level_switch = {
'debug': fileLogger.debug,
'info': fileLogger.info,
'warning': fileLogger.warning,
'error': fileLogger.error,
'critical': fileLogger.critical
}
console_logging_level_switch = {
'debug': consoleLogger.debug,
'info': consoleLogger.info,
'warning': consoleLogger.warning,
'error': consoleLogger.error,
'critical': consoleLogger.critical
}
Es hat zwei Funktionen:
def LoggingInit( logPath, logFile, html=True ):
global fileLogger
global consoleLogger
logFormatStr = "[%(asctime)s %(threadName)s, %(levelname)s] %(message)s"
consoleFormatStr = "[%(threadName)s, %(levelname)s] %(message)s"
if html:
logFormatStr = "<p>" + logFormatStr + "</p>"
# File Handler for log file
logFormatter = logging.Formatter(logFormatStr)
fileHandler = logging.FileHandler(
"{0}{1}.html".format( logPath, logFile ))
fileHandler.setFormatter( logFormatter )
fileLogger.addHandler( fileHandler )
# Stream Handler for stdout, stderr
consoleFormatter = logging.Formatter(consoleFormatStr)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter( consoleFormatter )
consoleLogger.addHandler( consoleHandler )
Und:
def WriteLog( string, print_screen=True, remove_newlines=True,
level='debug' ):
if remove_newlines:
string = string.replace('\r', '').replace('\n', ' ')
if print_screen:
console_logging_level_switch[level](string)
file_logging_level_switch[level](string)
Nenne ich LoggingInit
aus server.py
die initialisiert die Datei und console Logger. Ich rufen Sie dann WriteLog
aus ganz über dem Platz, so dass mehrere threads den Zugriff auf fileLogger
und consoleLogger
.
Brauche ich irgendwelche weiteren Schutz für meine log-Datei? Die Dokumentation besagt, dass die thread-locks werden von der Prozedur.
InformationsquelleAutor der Frage nckturner | 2013-06-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die gute Nachricht ist, dass Sie nicht brauchen zu tun nichts extra für die thread-Sicherheit, und Sie müssen entweder nichts extra oder fast etwas trivial für "clean shutdown". Ich werde die details später.
Die schlechte Nachricht ist, dass Ihr code hat ein großes problem sogar, bevor Sie zu diesem Punkt:
fileLogger
undconsoleLogger
sind das gleiche Objekt. Von die Dokumentation fürgetLogger()
:So, du bist immer der root-logger und speichern Sie es als
fileLogger
und dann bist du immer der root-logger und speichern Sie es alsconsoleLogger
. Also, inLoggingInit
initialisieren SiefileLogger
dann re-initialisieren das gleiche Objekt unter verschiedenen Namen mit unterschiedlichen Werten.Du kann fügen Sie mehrere Handler für den gleichen logger—und, da hier nur die Initialisierung, die Sie tatsächlich tun, ist für jeden
addHandler
Ihr code wird irgendwie funktionieren, aber nur durch Zufall. Und nur Art. Sie erhalten zwei Kopien von jeder Nachricht in die Protokolle, wenn Sie passprint_screen=True
und erhalten Sie Kopien in der Konsole, selbst wenn Sie passprint_screen=False
.Gibt es eigentlich keinen Grund für Globale Variablen; der springende Punkt, der
getLogger()
ist, dass Sie rufen Sie es jedes mal, wenn Sie es brauchen und Holen Sie das Globale root-logger, so dass Sie nicht brauchen, um es zu speichern und überall.Eine weitere kleinere problem ist, dass man nicht die Flucht der text, den Sie einfügen in HTML. An einem gewissen Punkt, Sie gehen zu versuchen, sich der string
"a < b"
und am Ende in Schwierigkeiten.Weniger ernst, eine Sequenz von
<p>
- tags, die nicht innerhalb einer<body>
innerhalb einer<html>
ist nicht ein gültiges HTML-Dokument. Aber viele Zuschauer kümmern, die automatisch, oder Sie können post-Prozess Ihre Protokolle trivial, bevor er Sie anzeigt. Aber wenn Sie wirklich wollen, dies zu korrigieren, müssen Sie UnterklasseFileHandler
und haben Ihre__init__
einen header hinzufügen, wenn gegeben, eine leere Datei und entfernen einer Fußzeile, wenn vorhanden, dann haben Sie Ihreclose
einen footer hinzufügen zu lassen.Zurück zu deiner eigentlichen Frage:
Benötigen Sie keine zusätzliche Verriegelung. Wenn ein handler korrekt implementiert
createLock
acquire
undrelease
(und es heißt, auf einer Plattform mit Gewinde), dem logging-Maschinen werden automatisch stellen Sie sicher, dass die Sperre, wenn erforderlich, stellen Sie sicher, dass jede Nachricht wird protokolliert, atomar.Soweit ich weiß, ist die Dokumentation nicht direkt sagen, dass
StreamHandler
undFileHandler
diese Methoden implementieren, es macht stark den Eindruck erwecken, es (der text, den Sie in der Frage genannten sagt "Das logging-Modul bestimmt werden, um thread-sicher ohne spezielle arbeiten benötigen, werden von Ihren Kunden", etc.). Und können Sie die Quelle für Ihre Umsetzung (z.B., CPython 3.3) und sehen, dass Sie beide Erben korrekt implementierte Methoden, die vonlogging.Handler
.Ebenfalls, wenn ein handler korrekt implementiert
flush
undclose
die logging-Maschinen werden sicherstellen, dass es abgeschlossen ordnungsgemäß während der normalen shutdown.Hier, die Dokumentation erklärt, was
StreamHandler.flush()
FileHandler.flush()
undFileHandler.close()
. Sie sind meist das, was Sie erwarten würde, außer, dassStreamHandler.close()
ist ein no-op, was bedeutet, es ist möglich, dass der Letzte log-Meldungen auf der Konsole verloren gehen können. Aus den docs:Wenn diese Fragen an Sie, und Sie möchten, um es zu beheben, müssen Sie etwas tun, wie dieses:
Und verwenden Sie dann
ClosingStreamHandler()
stattStreamHandler()
.FileHandler
hat kein solches problem.Den normalen Weg zu senden Protokolle an zwei Orten wird nur der root-logger mit zwei Handlern, die jeweils mit Ihren eigenen formatter.
Auch, selbst wenn Sie wollen, zwei Holzfäller, benötigen Sie keinen separaten
console_logging_level_switch
undfile_logging_level_switch
Karten; AufrufLogger.debug(msg)
ist genau das gleiche wie der AufrufLogger.log(DEBUG, msg)
. Dennoch müssen Sie einige Weg, um Ihre Karte benutzerdefinierten level-Namendebug
usw. zu den standard-NamenDEBUG
usw., aber Sie können nur tun, eine lookup, statt es zu tun einmal pro logger (plus, wenn Sie Ihre Namen sind nur die standard-Namen mit unterschiedlicher Besetzung, Sie betrügen können).Dies ist alles ziemlich gut beschrieben in der `Mehrere Hundeführer und-Formatierer Abschnitt, und der rest der logging-Kochbuch.
Das einzige problem mit der standard-Weg, dies zu tun ist, können Sie nicht einfach schalten Sie die Konsole Protokollierung auf einer Nachricht-um-Nachricht-basis. Das ist, weil es nicht eine normale Sache zu tun. In der Regel melden Sie sich einfach, indem Sie Ebenen, und legen Sie die log-Stufe höher auf der log-Datei.
Aber, wenn Sie mehr Kontrolle haben möchten, können Sie den Filter benutzen. Zum Beispiel, geben Sie Ihrem
FileHandler
einen filter, der alles akzeptiert, und IhreConsoleHandler
einen filter, der etwas verlangt, beginnend mitconsole
dann die filter'console' if print_screen else ''
. Das reduziertWriteLog
fast ein Einzeiler.Müssen Sie noch zwei zusätzliche Zeilen entfernen Zeilenumbrüche—aber können Sie das auch dass in den filter, oder über einen adapter, wenn Sie möchten. (Wieder, siehe das Kochbuch.) Und dann
WriteLog
wirklich ist ein one-liner.InformationsquelleAutor der Antwort abarnert
Python-logging ist thread-sicher:
Ist Python-logging-Modul, thread-sicher?
http://docs.python.org/2/library/logging.html#thread-safety
Also kein problem in der Python - (Bibliothek) - code.
Die routine, die Sie aufrufen aus mehreren threads (
WriteLog
) schreibt nicht auf einen gemeinsamen Staat. Sie haben also kein problem in deinem code.So sind Sie OK.
InformationsquelleAutor der Antwort andrew cooke