Qu'est-ce que le logging en Python ?
Le module logging fait partie de la bibliothèque standard et permet de capturer des événements dans notre application. Plus flexible que les print, il permet de savoir ce qui se passe dans notre code, du simple message d'information à l'erreur critique.
Quelle différence entre print et logging ?
On a souvent tendance à utiliser print pour du débogage (je suis le premier coupable).
Pour quelque chose de simple ou un débogage rapide, un print temporaire peut suffire.
Cependant, le module logging est la solution adaptée pour surveiller vos applications.
-
printpermet d’afficher des informations uniquement dans la console, alors queloggingpeut les envoyer vers la console, un fichier, un serveur distant ou même par e-mail -
printne permet pas de distinguer des niveaux d'importance, alors queloggingdéfinit différents seuils de criticité (DEBUG,INFO,WARNING,ERROR,CRITICAL) -
loggingenregistre automatiquement des métadonnées comme l’heure de l’événement, le fichier ou la ligne concernée -
Les appels à
printdoivent être supprimés manuellement pour cesser l'affichage, tandis queloggingpeut être désactivé via une configuration, sans modifier le code
Comment fonctionne un logger Python ?
Nous allons voir comment implémenter le logging, étape par étape, d'une utilisation basique à une utilisation un peu plus avancée. Bien que nous revenions plus tard sur ce concept, il faut savoir qu'il existe six niveaux de gravité : NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL.
Par défaut, Python ne logue qu'à partir du niveau WARNING :
import logging logging.debug("Ceci ne s'affichera pas") logging.info("Ceci non plus") logging.warning("Ceci s'affichera") logging.error("Ceci aussi")
Mettre en place son premier logging
Ici, nous allons simplement apprendre à nous passer du print. Commençons par importer le module logging et utilisons basicConfig pour dire au logger : « Affiche tout ce qui est au moins aussi important que le niveau INFO ». Enfin, nous utilisons logging.info à la place de print.
import logging # Configuration minimale : on règle le seuil de déclenchement sur INFO logging.basicConfig(level=logging.INFO) def envoyer_email(destinataire, sujet): logging.info(f"Préparation de l'email pour {destinataire}") # ... code d'envoi fictif ... logging.info(f"Email '{sujet}' envoyé avec succès !") envoyer_email("[email protected]", "Votre facture est disponible") # Résultat : # INFO:root:Préparation de l'email pour [email protected] # INFO:root:Email 'Votre facture est disponible' envoyé avec succès !
INFO est le niveau, root le nom du logger par défaut et le reste est votre message.
Enregistrer dans un fichier
Dans notre exemple précédent, le problème est que, lorsque l'on ferme la console, nos logs disparaissent avec elle. Nous allons voir comment écrire dans un fichier. Par exemple, pour des applications en production, vous conserverez vos logs dans un fichier afin de pouvoir consulter les éventuelles erreurs.
Nous utilisons le paramètre filename pour que Python puisse créer un fichier et écrire dedans, ainsi que le paramètre format pour l'affichage des logs.
import logging logging.basicConfig( filename='robot_aspirateur.log', # Le fichier sera créé automatiquement level=logging.WARNING, # On ne veut que les problèmes (WARNING et plus) format='%(asctime)s - %(levelname)s - %(message)s', filemode='a' # 'a' pour Append (ajouter à la fin) ) # Simulation d'événements logging.warning("Batterie faible (15%) - Retour à la base demandé") logging.error("Roue gauche bloquée : Chaussette détectée !")
Et dans le fichier de logs :
2026-01-26 09:26:42,618 - WARNING - Batterie faible (15%) - Retour à la base demandé 2026-01-26 09:26:42,619 - ERROR - Roue gauche bloquée : Chaussette détectée !
À noter
%(asctime)s, %(levelname)s et %(message)s agissent comme des balises : Python les remplacera automatiquement par l'heure exacte, le niveau de gravité et le contenu de votre message au moment de l'écriture.
Le logging dans un projet multimodule
Imaginons maintenant une application, Django par exemple, comprenant plusieurs fichiers. Les logs peuvent provenir de sources diverses et être écrits dans un seul fichier, mais nous voulons savoir de quel module provient l'anomalie.
Prenons un exemple de gestion des ressources humaines avec deux fichiers (oui, nous sommes minimalistes ici 😅) :
-
Dans le fichier principal
main.py, on configure le logging une seule fois (root) et sa configuration s'applique à tout le projet -
Dans le module
gestion_rh.py, on ne configure rien, on récupère juste un logger portant le nom du module viagetLogger(__name__)
# main.py import logging import gestion_rh # Notre module de gestion des employés # 1. Configuration unique du "Root Logger" logging.basicConfig( filename='paie.log', level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%H:%M:%S', filemode='w' # Pour écraser le fichier à chaque exécution ) # 2. Logger pour le script principal logger = logging.getLogger(__name__) logger.info("Lancement du logiciel de paie v2.0") # 3. Traitement des employés via le module externe gestion_rh.verser_salaire("Sophie") gestion_rh.verser_salaire("Patrick") # Le cas délicat...
#gestion_rh.py import logging # Ici, PAS de basicConfig. # On crée juste une instance de logger nommée 'gestion_rh' (grâce à __name__) logger = logging.getLogger(__name__) def verser_salaire(employe): logger.info(f"Traitement du dossier : {employe}") try: if employe == "Patrick": # Simulation d'une règle métier stricte raise ValueError("Erreur : Trop de pauses café, virement bloqué.") logger.info(f"Virement effectué avec succès pour {employe}.") except Exception: # L'argument exc_info=True ajoute la trace complète de l'erreur dans le log logger.error(f"Échec du virement pour {employe}", exc_info=True)
Sortie dans le fichier de log :
09:46:27 - __main__ - INFO - Lancement du logiciel de paie v2.0 09:46:27 - gestion_rh - INFO - Traitement du dossier : Sophie 09:46:27 - gestion_rh - INFO - Virement effectué avec succès pour Sophie. 09:46:27 - gestion_rh - INFO - Traitement du dossier : Patrick 09:46:27 - gestion_rh - ERROR - Échec du virement pour Patrick Traceback (most recent call last): File "/Users/gabrieltrouve/Pro/sandbox/gestion_rh.py", line 12, in verser_salaire raise ValueError("Erreur : Trop de pauses café, virement bloqué.") ValueError: Erreur : Trop de pauses café, virement bloqué.
On voit bien ici de quel fichier proviennent les différents logs.
Les niveaux de log
| Nom | Niveau | Quand utiliser |
|---|---|---|
| DEBUG | 10 | Informations détaillées pour diagnostiquer des problèmes, utile pendant le développement |
| INFO | 20 | Confirmation que les choses fonctionnent comme prévu, messages informatifs généraux |
| WARNING | 30 | Indication qu'un événement inattendu s'est produit ou pourrait se produire, mais l'application fonctionne encore |
| ERROR | 40 | Un problème sérieux s'est produit, une fonctionnalité n'a pas pu s'exécuter |
| CRITICAL | 50 | Erreur grave qui pourrait empêcher l'application de continuer à fonctionner |
À noter
-
Quand un logger a le niveau
NOTSET, il délègue au logger parent -
Si le logger racine (root) a
NOTSET, il utiliseWARNINGpar défaut
Le logger fonctionne en comparant le niveau du message avec le niveau configuré. La règle est simple : si le niveau du message est supérieur ou égal au niveau configuré, alors le message est affiché.