> Modules standards > Autres modules > Logging
Logging
On peut utiliser le module standard logging : import logging
Différents niveaux, le niveau par défaut étant WARNING et tout appel d'un niveau supérieur à celui défini produira un log :
- DEBUG : logging.debug('message')
- INFO : logging.info('message')
- WARNING : logging.warning('message')
- ERROR : logging.error('message')
- CRITICAL : logging.critical('message')
Pour régler le niveau de debug (et aussi le fichier d'output) :
- logging.basicConfig(filename = 'myFile.log', level = logging.DEBUG)
- les logs sont toujours rajoutés au fichier.
- si on veut effacer le fichier de log à chaque run, faire : logging.basicConfig(filename = 'myFile.log', filemode = 'w')
- attention, seulement un appel, les autres seront ignorés !
- attention, même si le niveau n'est pas suffisant pour générer le message, ce qui se trouve dans l'appel au logging est quand même évalué ! Et si ca finit en erreur, l'exception est levée.
On peut formatter les messages :
logging.basicConfig(level = logging.WARNING, format = '%(levelname)s:%(asctime)s:%(message)s', datefmt = '%Y-%m-%d %H:%M:%S')
- donne ici quelque chose comme : ERROR:2023-11-18 09:24:41:my message
- le format de date est le même que celui de time.strftime().
En général, on souhaite indiquer la provenance du logging :
Handlers : on définit un handler qui va s'occuper des messages, et on ajoute à logger un ou plusieurs handlers : le logger va passer les messages au handler qui va les traiter.
- StreamHandler : typiquement pour afficher sur la console, par défaut stderr : handler = logging.StreamHandler()
- FileHandler : handler = logging.FileHandler('mylog', mode = 'a') (mode = 'a' est le défaut, sinon, on peut utiliser 'w').
- handler = logging.NullHandler() : ne loggue pas du tout, utile dans une librairie pour laisser le choix à l'utilisateur de logguer ou non.
- il y a beaucoup d'autres handlers, par exemple RotatingFileHandler et on peut implémenter ses propres handler.
- logger.addHandler(myHandler) : rajoute un handler au logger. Les loggers fils en héritent aussi
- on peut fixer un level au handler, qui vient se rajouter au level du logger : myHandler.setLevel(logger.WARNING)
- exemple un peu complexe :
handler1 = logging.StreamHandler()
handler2 = logging.FileHandler('mylog', mode = 'a')
handler1.setFormatter(logging.Formatter(fmt = '%(name)s - %(levelname)s - %(message)s'))
handler2.setFormatter(logging.Formatter(fmt = '%(name)s - %(message)s'))
handler1.setLevel(logging.WARNING)
logger1 = logging.getLogger('toto')
logger1.addHandler(handler1)
logger2 = logging.getLogger('toto.titi')
logger2.addHandler(handler2)
logger1.setLevel(logging.INFO)
logger1.info('from logger1')
logger2.info('from logger2 (info)')
logger2.warning('from logger2 (warning)')
Si on configure un FileHandler, on a quand même aussi du log sur stderr car par défaut, le root logger a un StreamHandler défini (cf valeur de logging.getLogger().handlers). Pour éviter le logging sur la console :
- soit enlever ce handler : logging.getLogger().removeHandler(logging.getLogger().handlers[0])
- ou alors éviter la propagation : logger.propagate = False
Valeurs utilisables dans l'argument fmt des Formatters :
- %(message)s : le message.
- %(name)s : le nom du logger.
- %(asctime)s : date + heure.
- %(filename)s : le nom du fichier qui a généré le message.
- %(funcName)s : la fonction qui a généré le message.
- %(lineno)d : le numéro de ligne qui a généré le message.
- %(process)d : le process id.
- %(thread)d : le thread id.
Si l'action du logging est un peu couteuse, on peut tester si elle doit être faite :
if logger.isEnabledFor(logging.DEBUG):
logger.debug('Message with %s', myLongFunction())
Copyright python-simple.com
programmer en python, tutoriel python, graphes en python, Aymeric Duclert