Cours de Python / Déboguer les erreurs avec traceback et logging

Pour déboguer un programme Python, commencez par identifier l’exception et la ligne concernée dans le traceback, puis reproduisez les mêmes entrées. Le débogueur permet d’inspecter l’état pendant l’exécution ; le module logging conserve des événements classés par niveau de gravité.

Lire le traceback et isoler la cause

Un traceback décrit le chemin des appels qui a conduit à une exception. Lisez d’abord sa dernière ligne : elle indique généralement le type de l’exception et son message. Remontez ensuite jusqu’au fichier et à la ligne de votre propre code. Une erreur signalée dans une bibliothèque peut provenir de données incorrectes transmises par votre application ; modifier la bibliothèque en premier risque de masquer la cause.

Notez l’entrée qui échoue, la commande exécutée et l’interpréteur sélectionné. Réduisez ensuite le programme en conservant ce qui reproduit l’erreur. Comparez une entrée valide avec une entrée invalide en ne changeant qu’une valeur. La gestion des exceptions avec try et except explique comment une erreur remonte depuis une fonction appelée.

Pour observer les valeurs avant l’échec dans VS Code, installez les extensions Python et Python Debugger, sélectionnez l’interpréteur du projet et ouvrez le fichier. Cliquez dans la marge d’une ligne exécutable pour poser un point d’arrêt, puis choisissez Python Debugger: Debug Python File dans le menu du bouton d’exécution. À l’arrêt, examinez Variables et Call Stack ; avancez d’une instruction ou entrez dans une fonction pour comparer l’état obtenu à celui attendu. Arrêtez la session et retirez le point en cliquant de nouveau dans la marge. Les options disponibles sont décrites dans la documentation du débogueur Python de VS Code.

Exécuter un calcul avec des journaux

Le module logging appartient à la bibliothèque standard : ce script ne demande aucune dépendance supplémentaire. Enregistrez le programme complet ci-dessous en UTF-8 dans logging_demo.py, dans un dossier d’exercice. Depuis ce dossier, lancez python logging_demo.py avec l’environnement virtuel du projet activé. Si votre installation macOS ou Ubuntu utilise la commande python3 hors environnement virtuel, adaptez uniquement le nom de la commande.

import logging

logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
logger = logging.getLogger(__name__)

def calculate(amounts):
    logger.debug("count=%s", len(amounts))
    if any(x < 0 for x in amounts):
        raise ValueError("negative amount")
    return sum(amounts)

try:
    total = calculate([3500, 8000, 2500])
except ValueError:
    logger.exception("calculation failed")
    raise SystemExit(1)
else:
    logger.info("total=%s", total)
print("finished")
finished

Ce bloc de résultat représente uniquement la sortie standard, appelée stdout. Le journal contient aussi INFO:total=14000 sur la sortie d’erreur standard, stderr. Le code de sortie vaut zéro. Le message DEBUG indiquant le nombre de montants est filtré par le niveau INFO.

getLogger(__name__) nomme l’enregistreur d’après le module. basicConfig configure ici le traitement des journaux au lancement du script ; les marqueurs %s reçoivent les arguments du message. Dans une console interactive ou une application qui a déjà configuré ses gestionnaires, un nouvel appel à basicConfig peut ne rien modifier. Pour reproduire cet exercice, relancez un processus avec la commande du terminal.

Distinguer niveau, canal et état de sortie

Niveau Usage habituel
DEBUG Détails utiles au diagnostic, comme le nombre d’éléments reçus.
INFO Progression ou résultat normal d’une opération.
WARNING Situation inattendue à surveiller alors que le programme continue.
ERROR Échec d’une opération.
CRITICAL Problème grave pouvant empêcher le programme de continuer.

Fixez une convention cohérente pour l’application. Dans cet exemple, logger.exception s’utilise dans le gestionnaire d’exception et produit un message ERROR accompagné du traceback. print affiche le résultat destiné à l’utilisateur ; les journaux servent au diagnostic. Leur niveau et leur destination se configurent séparément, comme l’explique le tutoriel officiel de journalisation Python.

Un terminal peut afficher stdout et stderr ensemble. Un outil qui les collecte séparément peut donner l’impression que les lignes ont changé d’ordre : ne déduisez pas le déroulement du programme de ce seul affichage.

Enregistrer une erreur ne rend pas automatiquement l’exécution défaillante. Le gestionnaire du programme lève explicitement SystemExit(1) après le journal : dans ce script exécuté au premier plan, l’échec termine donc le processus avec le code 1. La ligne print("finished") n’est pas atteinte. Après la commande, consultez immédiatement $LASTEXITCODE dans PowerShell ou echo $? dans un shell macOS ou Ubuntu. La documentation de sys.exit détaille le rôle de SystemExit et des codes de sortie.

Provoquer une erreur et vérifier le retour à la normale

  1. Remplacez seulement 8000 par -1 dans l’appel à calculate. Relancez : stderr doit contenir ERROR:calculation failed, le chemin des appels et ValueError: negative amount. stdout reste vide et le code de sortie vaut 1.
  2. Rétablissez 8000, puis remplacez le niveau logging.INFO de basicConfig par logging.DEBUG. Dans un nouveau processus, vérifiez DEBUG:count=3, puis le total 14000 dans les journaux et finished dans stdout.
  3. Rétablissez INFO et relancez. Le détail count disparaît ; le total, finished et le code de sortie zéro restent inchangés.

Dans le traceback de l’échec, repérez l’appel à calculate, puis le raise dans la fonction : cette relation relie l’entrée négative au rejet. Un gestionnaire vide tel que except Exception: pass supprimerait l’information utile. Conservez le contexte nécessaire et transmettez un état d’échec lorsque l’appelant doit réagir.

Évitez d’enregistrer mots de passe, en-têtes d’authentification et dossiers personnels complets. Si les journaux vont dans un fichier, prévoyez son emplacement, ses permissions, sa rotation et sa durée de conservation. Écrire sans limite de gros objets dans une boucle consomme du temps et de l’espace ; gardez les valeurs nécessaires pour expliquer l’événement.