658 Stimmen

Logger Konfiguration zum Protokollieren in Datei und zum Ausdrucken auf die Standardausgabe

Ich verwende das Python-Logging-Modul, um einige Debug-Strings in eine Datei zu protokollieren, was ziemlich gut funktioniert. Jetzt möchte ich zusätzlich dieses Modul verwenden, um die Strings auch auf stdout auszugeben. Wie mache ich das? Um meine Strings in eine Datei zu protokollieren, verwende ich folgenden Code:

import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
    LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

und dann rufe eine Logger-Funktion wie

logger.debug("Ich werde in die Datei geschrieben")

Vielen Dank für die Hilfe!

0 Stimmen

Neugierig, wenn Sie den Level auf DEBUG ändern, wird es immer noch auf stdout UND in die Datei protokolliert? Ich glaube, es passiert nur, wenn es auf INFO eingestellt ist. Bitte korrigieren Sie mich, wenn ich falsch liege.

1 Stimmen

746voto

Waterboy Punkte 7032

Nur einen Handle auf den Root-Logger bekommen und den StreamHandler hinzufügen. Der StreamHandler schreibt auf stderr. Bin mir nicht sicher, ob Sie wirklich stdout über stderr benötigen, aber das ist das, was ich verwende, wenn ich den Python-Logger einrichte, und ich füge auch den FileHandler hinzu. Dann gehen alle meine Protokolle an beide Orte (das ist das, was Sie anscheinend möchten).

import logging
logging.getLogger().addHandler(logging.StreamHandler())

Wenn Sie die Ausgabe statt auf stderr auf stdout umleiten möchten, müssen Sie dies einfach im Konstruktor von StreamHandler angeben.

import sys
# ...
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))

Sie könnten auch einen Formatter hinzufügen, damit alle Ihre Protokollzeilen einen gemeinsamen Überschrift haben.

z.B.:

import logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")
rootLogger = logging.getLogger()

fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)

consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)

Gibt im Format aus:

2012-12-05 16:58:26,618 [MainThread  ] [INFO ]  meine Nachricht

25 Stimmen

Sie könnten auch einfach den StreamHandler mit sys.stdout initialisieren, und dann wird es auf diese Weise anstatt von stderr protokollieren.

1 Stimmen

@sr2222 logger.addHandler(sys.stdout) gibt mir den NameError: Name "sys" ist nicht definiert.

27 Stimmen

Nun ja... du musst zuerst import sys importieren. Und den Handler tatsächlich initialisieren, d.h. consoleHandler = logging.StreamHandler(sys.stdout)

671voto

Yirkha Punkte 10997

logging.basicConfig() kann seit Python 3.3 ein Schlüsselargument handlers entgegennehmen, was das Logging-Setup sehr vereinfacht, insbesondere beim Einrichten mehrerer Handler mit dem gleichen Formatter:

handlers – Wenn angegeben, sollte dies eine Iteration von bereits erstellten Handlern sein, die dem Root-Logger hinzugefügt werden sollen. Alle Handler, die noch keinen Formatter haben, erhalten den im Rahmen dieser Funktion erstellten Standard-Formatter zugewiesen.

Das gesamte Setup kann daher mit einem einzigen Aufruf wie folgt durchgeführt werden:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler()
    ]
)

(Oder mit import sys + StreamHandler(sys.stdout) gemäß den Anforderungen der ursprünglichen Frage - die Standardeinstellung für StreamHandler besteht darin, auf stderr zu schreiben. Werfen Sie einen Blick auf LogRecord-Attribute, wenn Sie das Protokollformat anpassen und Dinge wie Dateiname/Zeile, Thread-Info usw. hinzufügen möchten.)

Das obige Setup muss nur einmal zu Beginn des Skripts erfolgen. Sie können das Logging dann später von allen anderen Stellen im Code wie folgt verwenden:

logging.info('Nützliche Nachricht')
logging.error('Etwas Schlechtes ist passiert')
...

Hinweis: Falls es nicht funktioniert, hat wahrscheinlich jemand anderes das Logging-System bereits anders initialisiert. Kommentare schlagen vor, logging.root.handlers = [] vor dem Aufruf von basicConfig() durchzuführen.

8 Stimmen

Bitte nicht vergessen, level=logging.INFO oder das gewünschte Level ebenfalls festzulegen

8 Stimmen

Definition für FileHandler: logging.FileHandler(filename, mode='a', encoding=None, delay=False). Das bedeutet, dass wenn Sie einfach nur ein Protokoll im gleichen Ordner führen möchten, können Sie einfach FileHandler("mylog.log") verwenden. Wenn Sie das Protokoll jedes Mal überschreiben möchten, setzen Sie "w" als zweites Argument.

14 Stimmen

Ich habe das versucht, aber die Ausgabedatei ist leer, obwohl die Konsole die Ausgabe liefert.. Irgendwelche Vorschläge..?

91voto

Hazok Punkte 5035

Das Hinzufügen eines StreamHandlers ohne Argumente wird standardmäßig zu stderr anstelle von stdout führen. Wenn ein anderer Prozess von dem stdout-Dump abhängig ist (z. B. beim Schreiben eines NRPE-Plugins), stellen Sie sicher, dass Sie stdout explizit angeben, oder Sie könnten auf unerwartete Probleme stoßen.

Hier ist ein schnelles Beispiel, das die angenommenen Werte und LOGDATEI aus der Frage wiederverwendet:

import logging
from logging.handlers import RotatingFileHandler
from logging import handlers
import sys

log = logging.getLogger('')
log.setLevel(logging.DEBUG)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)

fh = handlers.RotatingFileHandler(LOGDATEI, maxBytes=(1048576*5), backupCount=7)
fh.setFormatter(format)
log.addHandler(fh)

0 Stimmen

Neugierig, wenn du den Level auf DEBUG änderst, wird es immer noch in stdout UND in die Datei protokolliert? Ich glaube, es passiert nur, wenn es auf INFO eingestellt ist. Bitte korrigiere mich, wenn ich falsch liege.

19voto

Silas Ray Punkte 25276

Führen Sie entweder basicConfig mit stream=sys.stdout als Argument aus, bevor Sie andere Handler einrichten oder Nachrichten protokollieren, oder fügen Sie manuell einen StreamHandler hinzu, der Nachrichten an stdout weiterleitet, zum Root-Logger (oder einem anderen gewünschten Logger).

2 Stimmen

Ich erhalte einen Fehler, wenn ich versuche, die Argumente stream und filename zusammen oder mit einem Handler zu verwenden.

15voto

Andrej Debenjak Punkte 1396

Protokollierung in stdout und rotierender Datei mit unterschiedlichen Ebenen und Formaten:

import logging
import logging.handlers
import sys

if __name__ == "__main__":

    # Ändern Sie die Stammprotokollerebene von WARNING (Standard) auf NOTSET, damit alle Nachrichten delegiert werden.
    logging.getLogger().setLevel(logging.NOTSET)

    # Fügen Sie den stdout-Handler hinzu, mit Ebene INFO
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(logging.INFO)
    formatter = logging.Formatter('%(name)-13s: %(levelname)-8s %(message)s')
    console.setFormatter(formatter)
    logging.getLogger().addHandler(console)

    # Fügen Sie den Datei-Rotationshandler hinzu, mit Ebene DEBUG
    rotatingHandler = logging.handlers.RotatingFileHandler(filename='rotating.log', maxBytes=1000, backupCount=5)
    rotatingHandler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    rotatingHandler.setFormatter(formatter)
    logging.getLogger().addHandler(rotatingHandler)

    log = logging.getLogger("app." + __name__)

    log.debug('Debug-Nachricht, sollte nur in der Datei erscheinen.')
    log.info('Info-Nachricht, sollte in Datei und stdout erscheinen.')
    log.warning('Warnungsnachricht, sollte in Datei und stdout erscheinen.')
    log.error('Fehlermeldung, sollte in Datei und stdout erscheinen.')

0 Stimmen

Beim Verwenden von \n und %s in der Protokollmeldung wird ValueError: unsupported format character 'n' (0x6e) at index 46 angezeigt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X