La journalisation Python ne produit rien


94

Dans un script python que j'écris, j'essaie de consigner les événements à l'aide du module de journalisation. J'ai le code suivant pour configurer mon enregistreur:

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)

Lorsque j'essaie de courir logging.debug("Some string"), je n'obtiens aucune sortie sur la console, même si cette page de la documentation indique que logging.debugl'enregistreur racine devrait afficher le message. Pourquoi mon programme ne produit-il rien et comment puis-je y remédier?

Réponses:


98

Le niveau de journalisation par défaut est avertissement. Puisque vous n'avez pas changé le niveau, le niveau de l'enregistreur racine est toujours un avertissement. Cela signifie qu'il ignorera toute journalisation avec un niveau inférieur à avertissement, y compris les journaux de débogage.

Ceci est expliqué dans le tutoriel :

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

La ligne «info» n'imprime rien, car le niveau est supérieur à info.

Pour changer le niveau, réglez-le simplement dans l'enregistreur racine:

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

En d'autres termes, il ne suffit pas de définir un gestionnaire avec level = DEBUG, le niveau de journalisation réel doit également être DEBUG afin de lui permettre de sortir quoi que ce soit.


6
La documentation indique que son niveau par défaut est NOTSET qui est un niveau de 0 qui devrait tout afficher ... Pourquoi ce n'est pas vrai?
Ben le

@Ben où est-ce que ça dit ça? Tout ce que je peux voir est "Le niveau par défaut est AVERTISSEMENT, ce qui signifie que seuls les événements de ce niveau et au-dessus seront suivis, sauf si le package de journalisation est configuré pour faire autrement."
Omri Barel


1
@Ben selon la documentation, les enregistreurs sont parcourus pour trouver le premier parent avec level != NOTSETou la racine (si aucun n'est trouvé). La racine a un WARNINGniveau par défaut. Ceci est écrit dans la section à laquelle vous avez lié ( Logger.setLevel).
Omri Barel

5
N'oubliez pas qu'après l'importation, loggingvous devez appeler logging.basicConfig()au moins une fois. Sinon, vous pourriez être très surpris que les enregistreurs enfants n'impriment rien. Les fonctions de journalisation sur l'enregistreur racine l'appellent paresseusement.
Hubert Grzeskowiak

58

Plusieurs années plus tard, il semble y avoir encore un problème de convivialité avec le journal Python. Voici quelques explications avec des exemples:

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)

Une source courante de confusion provient d'un enregistreur racine mal initialisé. Considère ceci:

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

Production:

woot
WARNING:myapp:woot

En fonction de votre environnement d'exécution et des niveaux de journalisation, la première ligne de journal (avant la configuration de base) peut ne pas apparaître nulle part .


Ma journalisation ne fonctionne pas, en ce sens qu'elle ne produit aucun fichier de sortie. Voyez-vous quelque chose que je fais qui est clairement mal? logging.basicConfig( filename='logging.txt', level=logging.DEBUG) logger = logging.getLogger() logger.info('Test B') logging.info('Test A')
Rylan Schaeffer

Le fichier journal n'est même pas créé
Rylan Schaeffer

J'ai remarqué que lorsque je laisse tomber un point de rupture après logger = logging.getLogger(), le niveau est réglé sur AVERTISSEMENT même si j'ai spécifié le niveau comme DEBUG. Sais-tu ce que je fais de mal?
Rylan Schaeffer

Bonjour @RylanSchaeffer, vous voudrez peut-être créer une nouvelle question et fournir quelques détails supplémentaires. Cela donnera également aux autres une chance de vous aider.
Hubert Grzeskowiak

J'ai fait. Souvent, poser un commentaire est un moyen plus rapide de trouver une réponse car au moins une personne bien informée verra ma question
Rylan Schaeffer

20

Pour tous ceux qui souhaitent une réponse très simple: définissez simplement le niveau que vous souhaitez afficher. En haut de tous mes scripts, je viens de mettre:

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

Ensuite, pour afficher quoi que ce soit à ou au-dessus de ce niveau:

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

Il s'agit d'un ensemble hiérarchique de cinq niveaux afin que les journaux s'affichent au niveau que vous avez défini, ou plus . Donc, si vous souhaitez afficher une erreur, vous pouvez utiliser logging.error("The plumbus is broken").

Les niveaux, dans l'ordre croissant de gravité, sont DEBUG, INFO, WARNING, ERRORet CRITICAL. Le paramètre par défaut est WARNING.

C'est un bon article contenant cette information mieux exprimée que ma réponse:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3


14

Essayez peut-être ceci? Il semble que le problème soit résolu après avoir supprimé tous les gestionnaires dans mon cas.

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

logging.basicConfig(filename='output.log', level=logging.INFO)

SyntaxError: invalid syntax
Eric

2
Pourquoi est-ce nécessaire? Quels gestionnaires sont fournis avec le logger python et pourquoi sont-ils là pour commencer? Ou peut-être que la question est: pourquoi basicConfig ne les remplace / ne les remplace-t-il pas?
jrh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.