Journalisation d'exceptions Python : conserver la trace et le contexte de requête
Utilisez un journalisateur nommé, configurez l'application une fois et attachez un contexte sûr sans dupliquer chaque erreur.
Dans ce guide
La réponse courte
Dans un gestionnaire d'exception, logger.exception enregistre un événement ERROR avec les informations de l'exception courante. Configurez les gestionnaires au point d'entrée de l'application et utilisez getLogger(__name__) dans les modules individuels. Incluez un identifiant d'opération ou de requête sûr afin que la trace puisse être reliée à l'action ayant échoué. La journalisation enregistre l'échec ; le programme doit décider séparément s'il faut récupérer, retourner une erreur ou relancer l'exception.
Choisir l'événement à enregistrer
Un objet exception et un événement opérationnel répondent à des questions différentes. L'exception décrit ce qui a échoué ; l'événement peut identifier quelle action était en cours. Avant d'ajouter de la journalisation, décidez qui lira l'enregistrement et ce dont il aura besoin pour enquêter. Un message court nommant l'opération et un identifiant de corrélation non secret sont généralement plus utiles que de répéter un corps de requête entier ou de déverser chaque variable locale.
Configurer la journalisation à la frontière de l'application
Pour un script autonome, configurez la journalisation avant que l'application ne commence à travailler. L'exemple ci-dessous utilise basicConfig une fois et obtient un journalisateur nommé. Une application plus grande peut utiliser un mécanisme de configuration différent, mais la responsabilité doit rester claire. Une bibliothèque réutilisable doit exposer des journalisateurs nommés et laisser son appelant choisir les gestionnaires, les destinations et les niveaux plutôt que de remplacer inconditionnellement la configuration de l'application.
Utiliser les informations de l'exception dans le gestionnaire
logger.exception est destiné à un gestionnaire d'exception, là où les informations de l'exception courante sont disponibles. Appeler logger.error avec seulement le texte de l'exception omet la trace, sauf si les informations de l'exception sont explicitement demandées. À l'inverse, écrire une trace ne nécessite pas de traiter chaque condition récupérable comme une défaillance fatale de l'application. Choisissez le niveau d'événement et la politique de récupération selon l'opération, et non uniquement selon le nom de la classe d'exception.
Lire un exemple complet et petit
Ce script autonome construit délibérément passe une chaîne non numérique à int. Le journal attendu contient un message ERROR avec request_id=demo1 et des informations d'exception se terminant par ValueError. Les chemins de trace exacts et les numéros de ligne dépendent de l'endroit où le script est enregistré, donc aucune trace complète fixe n'est promise. L'exemple démontre un appel de journalisation ; son exception interceptée n'est pas automatiquement propagée à l'appelant.
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")
logger = logging.getLogger(__name__)
request_id = "demo1"
try:
int("bad")
except ValueError:
logger.exception("Could not parse quantity; request_id=%s", request_id)
Décider qui possède l'enregistrement d'erreur final
Si une couche inférieure journalise une exception et la relance, et qu'une couche supérieure la journalise aussi, une défaillance peut apparaître deux fois. Décidez quelle couche a assez de contexte pour créer l'enregistrement opérationnel. Une couche inférieure peut ajouter des informations en levant une exception appropriée, tandis que la frontière journalise l'échec final. C'est un choix de conception plutôt qu'une exigence que chaque exception doit être journalisée exactement une fois partout.
Diagnostiquer une sortie répétée via les gestionnaires
Des enregistrements qui semblent dupliqués peuvent aussi résulter d'attacher un gestionnaire à un journalisateur enfant tout en permettant la propagation à un ancêtre qui a un autre gestionnaire. Inspectez la hiérarchie des journalisateurs et la configuration des gestionnaires avant de supprimer des événements d'application. Les niveaux du journalisateur et du gestionnaire peuvent tous deux affecter si la sortie apparaît. Supprimer la propagation sans comprendre les destinations peut masquer des enregistrements d'un collecteur central aussi bien que supprimer une ligne de console dupliquée.
Garder le contexte sensible hors de l'enregistrement
Utilisez un identifiant de requête opaque ou un nom d'opération soigneusement choisi. N'incluez pas de mots de passe, d'en-têtes d'autorisation, de clés API ou d'une charge utile de requête entière non filtrée. Les messages d'exception eux-mêmes peuvent contenir des entrées utilisateur ou des détails de connexion, donc un appel de journalisation sûr n'est pas la preuve que chaque trace résultante est sûre à conserver. Appliquez des politiques d'accès, de rétention et de rougeur appropriées à l'application réelle et à la destination des journaux.
Séparer le diagnostic du comportement du programme
Un appel de journalisation ne réessaie pas l'opération ni ne sélectionne la réponse renvoyée à un client. Après avoir enregistré l'événement, choisissez délibérément s'il faut continuer avec un repli valide, retourner une défaillance documentée, ou relancer. Documentez le choix près de la frontière d'erreur. Si le programme continue, évitez de faire dépendre le code ultérieur d'une valeur qui n'a jamais été créée avec succès par l'instruction ayant échoué.
Points à vérifier
- Configurez les gestionnaires dans l'application, pas dans chaque module.
- Utilisez les informations de l'exception pendant la gestion de l'exception.
- Incluez un identifiant de corrélation sûr.
- Inspectez les gestionnaires et la propagation quand la sortie se répète.
- Définissez la récupération ou la propagation séparément de la journalisation.
Champ d’application
Le script illustre la journalisation de la bibliothèque standard et une ValueError interceptée. Il ne s'agit pas d'une configuration de journalisation de production complète et il ne démontre pas un collecteur de journaux déployé, de rougeur automatique, de nouvelles tentatives ou un test d'application exécuté.