Python-Protokollierung gibt nichts aus

91

In einem Python-Skript, das ich schreibe, versuche ich, Ereignisse mithilfe des Protokollierungsmoduls zu protokollieren. Ich habe den folgenden Code, um meinen Logger zu konfigurieren:

ERROR_FORMAT = "%(levelname)s at %(asctime)s in %(funcName)s in %(filename) at line %(lineno)d: %(message)s"
DEBUG_FORMAT = "%(lineno)d in %(filename)s at %(asctime)s: %(message)s"
LOG_CONFIG = {'version':1,
              'formatters':{'error':{'format':ERROR_FORMAT},
                            'debug':{'format':DEBUG_FORMAT}},
              'handlers':{'console':{'class':'logging.StreamHandler',
                                     'formatter':'debug',
                                     'level':logging.DEBUG},
                          'file':{'class':'logging.FileHandler',
                                  'filename':'/usr/local/logs/DatabaseUpdate.log',
                                  'formatter':'error',
                                  'level':logging.ERROR}},
              'root':{'handlers':('console', 'file')}}
logging.config.dictConfig(LOG_CONFIG)

Wenn ich versuche auszuführen logging.debug("Some string"), erhalte ich keine Ausgabe an die Konsole, obwohl auf dieser Seite in den Dokumenten angegeben ist , dass logging.debugder Root-Logger die Nachricht ausgeben soll. Warum gibt mein Programm nichts aus und wie kann ich das beheben?

murgatroid99
quelle

Antworten:

97

Die Standardprotokollierungsstufe ist Warnung. Da Sie die Ebene nicht geändert haben, warnt die Ebene des Root-Loggers immer noch. Dies bedeutet, dass jede Protokollierung mit einer niedrigeren Stufe als der Warnung ignoriert wird, einschließlich Debug-Protokollierungen.

Dies wird im Tutorial erklärt :

import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything

Die 'Info'-Zeile gibt nichts aus, da der Level höher als der Info ist.

Um die Ebene zu ändern, legen Sie sie einfach im Root-Logger fest:

'root':{'handlers':('console', 'file'), 'level':'DEBUG'}

Mit anderen Worten, es reicht nicht aus, einen Handler mit level = DEBUG zu definieren. Die tatsächliche Protokollierungsstufe muss ebenfalls DEBUG sein, damit er etwas ausgibt.

Omri Barel
quelle
6
Die Dokumentation besagt, dass die Standardstufe NOTSET ist, eine Stufe von 0, die alles ausgeben soll ... Warum ist das nicht wahr?
Ben
@ Ben wo steht das? Alles, was ich sehen kann, ist "Die Standardstufe ist WARNUNG, was bedeutet, dass nur Ereignisse dieser Stufe und höher verfolgt werden, sofern das Protokollierungspaket nicht anders konfiguriert ist."
Omri Barel
1
@Ben Gemäß den Dokumenten werden die Logger durchlaufen, um das erste übergeordnete Element mit level != NOTSEToder das Stammverzeichnis zu finden (falls keines gefunden wird). Die Wurzel hat WARNINGstandardmäßig eine Ebene. Dies ist in dem Abschnitt geschrieben, den Sie mit ( Logger.setLevel) verlinkt haben .
Omri Barel
5
Beachten Sie, dass Sie nach dem Import mindestens einmal logginganrufen müssen logging.basicConfig(). Andernfalls könnten Sie sehr überrascht sein, dass untergeordnete Logger nichts drucken. Protokollierungsfunktionen auf dem Root-Logger rufen es träge auf.
Hubert Grzeskowiak
53

Viele Jahre später scheint es immer noch ein Usability-Problem mit dem Python-Logger zu geben. Hier einige Erklärungen mit Beispielen:

import logging
# This sets the root logger to write to stdout (your console).
# Your script/app needs to call this somewhere at least once.
logging.basicConfig()

# By default the root logger is set to WARNING and all loggers you define
# inherit that value. Here we set the root logger to NOTSET. This logging
# level is automatically inherited by all existing and new sub-loggers
# that do not set a less verbose level.
logging.root.setLevel(logging.NOTSET)

# The following line sets the root logger level as well.
# It's equivalent to both previous statements combined:
logging.basicConfig(level=logging.NOTSET)


# You can either share the `logger` object between all your files or the
# name handle (here `my-app`) and call `logging.getLogger` with it.
# The result is the same.
handle = "my-app"
logger1 = logging.getLogger(handle)
logger2 = logging.getLogger(handle)
# logger1 and logger2 point to the same object:
# (logger1 is logger2) == True


# Convenient methods in order of verbosity from highest to lowest
logger.debug("this will get printed")
logger.info("this will get printed")
logger.warning("this will get printed")
logger.error("this will get printed")
logger.critical("this will get printed")


# In large applications where you would like more control over the logging,
# create sub-loggers from your main application logger.
component_logger = logger.getChild("component-a")
component_logger.info("this will get printed with the prefix `my-app.component-a`")

# If you wish to control the logging levels, you can set the level anywhere 
# in the hierarchy:
#
# - root
#   - my-app
#     - component-a
#

# Example for development:
logger.setLevel(logging.DEBUG)

# If that prints too much, enable debug printing only for your component:
component_logger.setLevel(logging.DEBUG)


# For production you rather want:
logger.setLevel(logging.WARNING)

Eine häufige Quelle der Verwirrung ist ein schlecht initialisierter Root-Logger. Bedenken Sie:

import logging
log = logging.getLogger("myapp")
log.warning("woot")
logging.basicConfig()
log.warning("woot")

Ausgabe:

woot
WARNING:myapp:woot

Abhängig von Ihrer Laufzeitumgebung und den Protokollierungsstufen wird die erste Protokollzeile (vor der Grundkonfiguration) möglicherweise nirgendwo angezeigt .

Hubert Grzeskowiak
quelle
Meine Protokollierung funktioniert nicht, da sie keine Ausgabedatei erzeugt. Sehen Sie etwas, was ich tue, das eindeutig falsch ist? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
Rylan Schaeffer
Die Protokolldatei wird noch nicht einmal erstellt
Rylan Schaeffer
Ich habe festgestellt, dass beim Ablegen eines Haltepunkts logger = logging.getLogger()der Pegel auf WARNUNG gesetzt ist, obwohl ich den Pegel als angegeben habe DEBUG. Weißt du was ich falsch mache?
Rylan Schaeffer
Hallo @RylanSchaeffer, vielleicht möchten Sie eine neue Frage erstellen und weitere Details angeben. Dies gibt auch anderen die Möglichkeit, Ihnen zu helfen.
Hubert Grzeskowiak
Ich tat. Häufig ist das Stellen eines Kommentars eine schnellere Möglichkeit, eine Antwort zu finden, da mindestens eine sachkundige Person meine Frage sehen wird
Rylan Schaeffer
16

Für alle hier, die eine supereinfache Antwort wünschen: Stellen Sie einfach die gewünschte Ebene ein. Ganz oben in all meinen Skripten habe ich Folgendes eingefügt:

import logging
logging.basicConfig(level = logging.INFO)

Um dann etwas auf oder über dieser Ebene anzuzeigen:

logging.info("Hi you just set your fleeb to level plumbus")

Es handelt sich um einen hierarchischen Satz von fünf Ebenen, sodass Protokolle auf der von Ihnen festgelegten Ebene oder höher angezeigt werden . Wenn Sie also einen Fehler anzeigen möchten, können Sie ihn verwenden logging.error("The plumbus is broken").

Die Ebene, in der Reihenfolge der Schwere zunimmt, sind DEBUG, INFO, WARNING, ERROR, und CRITICAL. Die Standardeinstellung ist WARNING.

Dies ist ein guter Artikel, der diese Informationen enthält, die besser ausgedrückt werden als meine Antwort:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3

Eric
quelle
14

Vielleicht versuchen Sie das? Es scheint, dass das Problem gelöst ist, nachdem alle Handler in meinem Fall entfernt wurden.

for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

logging.basicConfig(filename='output.log', level=logging.INFO)
yue dong
quelle
SyntaxError: invalid syntax
Eric
2
Warum ist das notwendig? Welche Handler werden mit dem Python-Logger ausgeliefert und warum sind sie zunächst da? Oder vielleicht ist die Frage, warum basicConfig sie nicht überschreibt / ersetzt?
jrh