Question Comment imprimer le retraçage complet sans arrêter le programme?


J'écris un programme qui analyse 10 sites Web, localise des fichiers de données, enregistre les fichiers, puis les analyse pour créer des données facilement utilisables dans la bibliothèque NumPy. Il y a tonnes des erreurs rencontrées par ce fichier à cause de mauvais liens, d'un XML mal formé, d'entrées manquantes et d'autres choses que je n'ai pas encore catégorisées. J'ai initialement fait ce programme pour gérer des erreurs comme celles-ci:

try:
    do_stuff()
except:
    pass

Mais maintenant je veux enregistrer les erreurs:

try:
    do_stuff()
except Exception, err:
    print Exception, err

Notez que cela imprime dans un fichier journal pour une révision ultérieure. Cela imprime généralement des données très inutiles. Ce que je veux c'est imprimer exactement les mêmes lignes imprimées quand l'erreur se déclenche sans essayer-sauf intercepter l'exception, mais je ne veux pas qu'elle arrête mon programme puisqu'elle est imbriquée dans une série de boucles for que je voudrais voir à la fin


494
2017-09-13 17:03


origine


Réponses:


Certaines autres réponses ont déjà souligné le traceback module.

S'il vous plaît noter qu'avec print_excDans certains cas, vous n'obtiendrez pas ce que vous attendez. En Python 2.x:

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

... affichera la trace du dernier exception:

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

Si vous avez vraiment besoin d'accéder à l'original traceback une solution consiste à mettre en cache le infos sur l'exception comme retourné de exc_info dans une variable locale et l'afficher en utilisant print_exception:

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

Produire:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

Peu de pièges avec cela cependant:

  • De la doc de sys_info:

    L'affectation de la valeur de retour de traceback à une variable locale dans une fonction qui gère une exception entraînera référence circulaire. Cela empêchera tout ce qui est référencé par une variable locale dans la même fonction ou par la traceback d'être collecté. [...] Si vous avez besoin de la trace, veillez à la supprimer après utilisation (mieux fait avec un essai ... enfin la déclaration)

  • mais, du même doc:

    À partir de Python 2.2, ces cycles sont automatiquement récupérés lorsque le garbage collection est activé et qu'ils deviennent inaccessibles, il reste plus efficace d'éviter de créer des cycles.


D'autre part, en vous permettant d'accéder à la traceback associé à une exception, Python 3 produit un résultat moins surprenant:

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

... Affichera:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

313
2018-06-05 18:05



traceback.format_exc() ou sys.exc_info() donnera plus d'informations si c'est ce que vous voulez.

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[0])

517
2017-09-13 17:27



Si vous êtes en train de déboguer et que vous voulez simplement voir la trace de la pile actuelle, vous pouvez simplement appeler:

traceback.print_stack()

Il n'est pas nécessaire de déclencher manuellement une exception juste pour l'attraper à nouveau.


154
2018-04-28 21:40



Comment imprimer le retraçage complet sans arrêter le programme?

Lorsque vous ne voulez pas arrêter votre programme sur une erreur, vous devez gérer cette erreur avec un try / except:

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

Pour extraire le retraçage complet, nous utiliserons le traceback module de la bibliothèque standard:

import traceback

Et pour créer une stacktrace compliquée pour démontrer que nous obtenons la pile complète:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Impression

À impression la trace complète, utilisez le traceback.print_exc méthode:

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

Qui imprime:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Mieux que l'impression, la journalisation:

Cependant, une bonne pratique consiste à configurer un enregistreur pour votre module. Il connaîtra le nom du module et pourra changer de niveau (parmi d'autres attributs, tels que les gestionnaires)

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

Dans ce cas, vous voudrez le logger.exception fonction plutôt:

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

Quels journaux:

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Ou peut-être vous voulez juste la chaîne, auquel cas, vous voudrez le traceback.format_exc fonction plutôt:

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

Quels journaux:

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

Conclusion

Et pour les trois options, nous voyons que nous obtenons le même résultat que lorsque nous avons une erreur:

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

54
2017-07-16 03:23



Pour obtenir le précis trace de pile, sous forme de chaîne, qui aurait ont été augmentés si aucun essai / excepté était là pour enjamber, placez simplement ceci dans le bloc except qui attrape l'exception fautive.

desired_trace = traceback.format_exc(sys.exc_info())

Voici comment l'utiliser (en supposant flaky_func est défini, et log appelle votre système de journalisation préféré):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

C'est une bonne idée d'attraper et de relancer KeyboardInterrupts, de sorte que vous pouvez toujours tuer le programme en utilisant Ctrl-C. La journalisation est en dehors de la portée de la question, mais une bonne option est enregistrement. Documentation pour le sys et traceback modules.


6
2017-11-15 18:09



Vous devrez mettre try / excepté dans la boucle la plus interne où l'erreur peut se produire, c'est-à-dire

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... etc

En d'autres termes, vous aurez besoin d'encapsuler les instructions qui peuvent échouer dans try / excepté aussi spécifique que possible, dans la boucle la plus interne possible.


5
2017-09-13 17:10



Vous voulez le traceback module. Il vous permettra d'imprimer des sauvegardes de pile comme le fait normalement Python. En particulier, print_last La fonction imprime la dernière exception et une trace de pile.


2
2017-09-13 17:11