Tenir un fichier de log avec Python
Il est souvent intéressant de tenir un fichier de log dans plusieurs situations, comme archiver différentes erreurs, ou même pour les débugs. Python fournis nativement un module pour faire cela, soit en console ou dans un fichier, et permettant plusieurs degrés de logs, du message de débug aux erreurs critiques.
Ce module permet d’aller bien plus loin de ce que j’en aurai besoin, comme un serveur de log pour centraliser les logs de clients, des logs tournantes ou encore l’envoi par SMTP (mail). Il n’est pas question ici de tout voir, mais simplement tenir un fichier de log facilement.
Les niveaux de messages :
- Debug
- Info
- Warning
- Error
- Critical
Note: Je me suis servis de Python3 tout au long de ce billet, mais l’utilisation du logger doit être similaire pour Python2
Premier essai
essayons un script rapide, qui n’a pas vraiment d’intérêt si ce n’est de voir ce qu’il s’y passe.
# -*- coding: utf-8 -*-
import logging
logging.warning('coin')
logging.debug('pan!')
On execute le programme, et on obtient la sortie suivante :
WARNING:root:coin
Plusieurs remaques:
- Seul le warning s’est affiché, c’est parce que par défaut, les messages qui ont un niveau à partir de warning sont affiché, pouvant être modifié.
- La sortie contient le niveau (WARNING), un ‘root’ un peu obscure, et le message, la sortie n’est pas très jolie, mais fait ce qu’on lui demande.
- Le message est envoyé en console et n’est pas loggé dans un fichier comme nous le souhaitons.
Fichier et niveau de log
Puisqu’on peut souhaiter logger dans un fichier, utile par exemple si le programme est écrit en ncurses, mais également pour avoir des informations sur une plus longue période.
Dans le script précédent, on rajoute avant les messages de warning et debug la ligne suivante :
On exécute et regarde le fichier prog.log, on obtient exactement à quoi l’on s’attendait, les deux messages.
Logger les variables
Comme il peut être utile de logger quelques variables, on peut le faire en ajoutant les variables comme argument comme dans l’exemple suivant :
a = 'coin'
b = 'pan!'
logging.warning('a:%s b:%s', a, b)
La sortie sera la suivante :
WARNING:root:a:coin b:pan!
Ajouter l’heure aux messages
Dans un fichier de log, on souhaite généralement avoir à chaque message, une indication de l’heure, et éventuellement de la date, il est possible de le faire, une fois pour toute, de la façon suivante :
# -*- coding: utf-8 -*-
import logging
import time
logging.basicConfig(
filename='prog.log',
level=logging.INFO,
format='%(asctime)s %(levelname)s - %(message)s',
datefmt='%d/%m/%Y %H:%M:%S',
)
logging.info('Mon programme démarre')
time.sleep(2)
logging.warning('Oh, quelque chose ce passe!')
logging.info('fin du prog')
Nous obtenons dans le fichier de log les informations suivantes :
16/07/2011 13:33:28 WARNING - Oh, quelque chose ce passe!
16/07/2011 13:33:28 INFO - fin du prog
La sortie est plus lisible et exploitable.
Fichier de configuration
Pour avoir la possibilité de séparer la configuration du logger et le code en général, il est possible de tenir un fichier spécifique à la configuration, il supporte deux syntaxes différentes, basé sur ConfigParser ou YAML.
Comme ce module permet un niveau de customisation assez avancé, il est normal que cela se ressente sur la verbosité du fichier de configuration. Pour ma part, je ne pense pas en avoir besoin dans l’immédiat, donc je vous renvoi sur la documentation officiel, et notamment ce how-to qui est un bon endroit pour commencer, et dont ce billet s’en inspire fortement.