Logging

[wiki: Journalisation]

PageOutline

La notion de « logging » consiste a tracer le fonctionnement d’un programme en envoyant
des messages sur différents canaux (console, fichier, mail, reseau,…), avec
différents niveaux d’importance et la possibilité de filtrer les messages en
fonction de ces niveaux. Python possège un module standard pour le faire : le
module logging.

== Exemple simple

5 niveaux de criticité sont prédéfinis par défaut :

  • CRITICAL (C) : erreur sévère au point de provoquer l’arrêt de l’application.
  • ERROR (E) : erreur non fatale au programme.
  • WARNING (W) : élément anormal, mais qui n’est pas nécessairement une erreur.
  • INFO (I) : information d’exécution normale.
  • DEBUG (D) : excessivement détaillé, pour le débogage.

Pour chaque canal de diffusion, on doit sélectionner un seuil de sensibilité
parmi les précédents, et le canal ne retiendra que les affichages d’un niveau
supérieur ou égal au seuil.

En général, le programmeur fait en sorte que le seuil puisse être
ajusté par l’utilisateur au lancement de l’application.

Exemple simple ou tous les messages sont conservés dans
un fichier :

#!python
import logging


logging.basicConfig(filename='essai.log',level=logging.DEBUG,
format='%(asctime)s -- %(name)s -- %(levelname)s -- %(message)s')

logging.debug('Debug message')
logging.info('Info message')
logging.warning('Warning message')
logging.error('Error message')
logging.critical('Critical message')


Pour personnaliser le format d’affichage, l’ensemble des variables
disponibles est ici.

== Enregistreurs (logger), gestionnaires (handler) et formatteurs (formatter)

Dans l’exemple simpliste ci-dessus, même si ils n’apparaissent pas,
interviennents en réalité un enregistreur principal (logger),
nommé «  » (ou « root »), et un gestionnaire (handler) chargé de la
transmission des messages au fichier.

Chaque canal de diffusion est contrôlé par un « gestionnaire » (handler),
et un enregistreur peut diffuser simultanément sur plusieurs canaux,
chacun avec son propre gestionnaire, son propre seuil de sensibilité et
son formatteur (Formatter) spécifique.

Ci-dessous, un exemple qui enregistre toute l’information dans un fichier,
et l’information « non debug » sur la console.

#!python
import logging


console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter())
console_handler.setLevel(logging.INFO)

file_handler = logging.FileHandler(file[:-3]+".log", mode="w", encoding="utf-8")
file_handler.setFormatter(logging.Formatter("%(asctime)s :: %(name)s :: %(levelname)s :: %(message)s"))
file_handler.setLevel(logging.DEBUG)

logger = logging.getLogger("main")
logger.setLevel(logging.DEBUG)
logger.addHandler(console_handler)
logger.addHandler(file_handler)

logger.info('================')
logger.debug ('Debug message')
logger.info ('Info message')
logger.warning ('Warning message')
logger.error ('Error message')
logger.critical('Critical message')


== Utiliser un même enregistreur dans plusieurs modules

La liste de tous les enregistreurs créés, avec leurs noms, est
centralisée dans le module logging, et vous pouvez récupérez
ces enregistreurs depuis n’importe quel module, par le biais
d’un appel à logging.getLogger(<le-nom>) avec le nom
approprié.

Si vous voulez utilisez le même enregistreur partout, utilisez
l’enregistreur racine, de nom «  », dans tous vos modules. Un
des modules, ou le programme principal, étant chargé de
configurer correctement cet enregistreur, si possible
précocement, avant qu’il soit utilisé par quiconque.

== Bonnes pratiques

Préférez log.debug('My debug message %s',myobject) à log.debug('My debug message %s' % myobject). Dans le premier cas, la transformation de myobject) en chaine de caractères, qui peut passer par des opérations couteuses, n’est appliquée que si le seuil logging.DEBUG est actif et l’affichage nécessaire.

Références