J'ai un simple script Python qui utilise le logging
intégré).
Je configure la journalisation dans une fonction. La structure de base serait quelque chose comme ceci:
#!/usr/bin/env python
import logging
import ...
def configure_logging():
logger = logging.getLogger("my logger")
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
return logger
def count_parrots():
...
logger.debug??
if __== '__main__':
logger = configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()
Je peux bien appeler l'enregistreur de l'intérieur __main__
. Cependant, comment appeler l'enregistreur depuis la fonction count_parrots ()? Quelle est la façon la plus pythonique de gérer la configuration d'un enregistreur comme celui-ci?
Vous pouvez soit utiliser l'enregistreur racine (par défaut), et donc les fonctions de niveau module logging.debug
, ... ou obtenez votre enregistreur dans la fonction en l'utilisant. En effet, la fonction getLogger
est une fonction de type usine avec un registre (de type singleton), c'est-à-dire qu'elle renvoie toujours la même instance pour le nom de l'enregistreur donné. Vous pouvez ainsi récupérer votre logger dans count_parrots en utilisant simplement
logger = logging.getLogger("my logger")
au début. Cependant, la convention consiste à utiliser un nom hiérarchique en pointillés pour votre enregistreur. Voir http://docs.python.org/library/logging.html#logging.getLogger
ÉDITER:
Vous pouvez utiliser un décorateur pour ajouter le comportement de journalisation à vos fonctions individuelles, par exemple:
def debug(loggername):
logger = logging.getLogger(loggername)
def log_(enter_message, exit_message=None):
def wrapper(f):
def wrapped(*args, **kargs):
logger.debug(enter_message)
r = f(*args, **kargs)
if exit_message:
logger.debug(exit_message)
return r
return wrapped
return wrapper
return log_
my_debug = debug('my.logger')
@my_debug('enter foo', 'exit foo')
def foo(a, b):
return a+b
vous pouvez "coder en dur" le nom de l'enregistreur et supprimer la fermeture de niveau supérieur et my_debug.
Vous pouvez simplement faire:
logger = logging.getLogger("my logger")
dans votre méthode count_parrots()
. Lorsque vous transmettez le nom utilisé précédemment (c'est-à-dire "mon enregistreur"), le module de journalisation renvoie la même instance qui a été créée correspondant à ce nom.
Mise à jour: à partir du tutoriel de journalisation (emphais mine)
getLogger () renvoie une référence à une instance d'enregistreur avec le nom spécifié s'il est fourni, ou root dans le cas contraire. Les noms sont des structures hiérarchiques séparées par des périodes. Plusieurs appels à getLogger () avec le même nom renverront une référence au même objet logger.
La manière typique de gérer la journalisation est d'avoir un enregistreur par module stocké dans une variable globale. Toutes les fonctions et méthodes de ce module font alors simplement référence à la même instance de l'enregistreur.
Ceci est discuté brièvement dans l'introduction du tutoriel de journalisation avancée dans la documentation: http://docs.python.org/howto/logging.html#advanced-logging-tutorial
Vous pouvez transmettre des instances d'enregistreur comme paramètres, mais cela est généralement rare.
Si vous n'avez pas besoin des messages de journal sur votre console, vous pouvez les utiliser de manière minimaliste.
Vous pouvez également utiliser tail -f myapp.log
pour voir les messages sur la console.
import logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', \
filename='myapp.log', \
level=logging.INFO)
def do_something():
logging.info('Doing something')
def main():
logging.info('Started')
do_something()
logging.info('Finished')
if __== '__main__':
main()
J'ai été confus par le fonctionnement des variables globales en Python. Dans une fonction, vous devez seulement déclarer global logger
Si vous faites quelque chose comme logger = logging.getLogger("my logger")
et espérez modifier le global logger
.
Ainsi, pour modifier votre exemple, vous pouvez créer un objet enregistreur global au début du fichier. Si votre module peut être importé par un autre, vous devez ajouter le NullHandler
afin que si l'importateur de la bibliothèque ne souhaite pas que la journalisation soit activée, il n'a aucun problème avec votre lib ( ref ).
#!/usr/bin/env python
import logging
import ...
logger = logging.getLogger("my logger").addHandler(logging.NullHandler())
def configure_logging():
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
def count_parrots():
...
logger.debug('counting parrots')
...
return parrots
if __== '__main__':
configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()