Como imprimir o traceback completo sem parar o programa?

estou a escrever um programa que analisa 10 websites, localiza ficheiros de dados, guarda os ficheiros, e depois analisa-os para fazer dados que possam ser facilmente usados na biblioteca NumPy. Existem toneladas de erros que este ficheiro encontra através de ligações más, XML mal formado, entradas em falta e outras coisas que ainda não categorizei. Inicialmente fiz este programa para lidar com erros como este:

try:
    do_stuff()
except:
    pass

mas agora quero registar erros:

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

Note que esta é a impressão num ficheiro de registo para revisão posterior. Isto normalmente imprime dados inúteis. O que eu quero é imprimir exatamente as mesmas linhas impressas quando o erro despoleta sem a tentativa-exceto interceptar a exceção, mas eu não quero que ele pare o meu programa, uma vez que ele é aninhado em uma série de loops para que eu gostaria de ver para completar.

8 answers

Alguma outra resposta já indicou o módulotraceback .

Por favor, note que com print_exc, em alguns casos de Canto, você não vai obter o que você poderia esperar. Em Python 2.x:

import traceback

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

    traceback.print_exc()

...irá mostrar a localização do último excepção:

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

Se você realmente precisa acessar o original traceback uma solução é colocar o exceção infos como devolvidos exc_info em um local variável e visualizá-la com 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

Produzindo:

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!
Mas há poucas armadilhas com isto.
  • Do doc de sys_info:

    Atribuir o valor de retorno de traceback a uma variável local numa função que está a lidar com uma excepção irá causar uma referência circular . Isto impedirá que qualquer coisa referenciada por uma variável local na mesma função ou pelo traceback seja recolhida no lixo. [...] Se você precisar do traceback, certifique-se de apagá-lo após o uso (melhor feito com uma tentativa ... declaração final)

  • Mas, do mesmo doc:

    Começando com o Python 2.2, esses ciclos são automaticamente recuperados quando a coleta de lixo é ativada e eles se tornam inalcançáveis, mas permanece mais eficiente para evitar a criação de ciclos.


Por outro lado, permitindo-lhe aceder ao traceback associado a uma excepção, o Python 3 produz um resultado menos surpreendente:
import traceback

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

    traceback.print_tb(err.__traceback__)

... irá mostrar:

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")
 342
Author: Sylvain Leroux, 2015-06-22 14:43:00

traceback.format_exc() ou sys.exc_info() vai dar mais informações, se é isso que queres.

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[0])
 534
Author: volting, 2016-06-14 21:03:52

Se está a depurar e só quer ver o traço actual da pilha, pode simplesmente ligar para:

traceback.print_stack()

Não há necessidade de abrir uma excepção manualmente só para voltar a apanhá-la.
 165
Author: dimo414, 2015-05-19 06:38:36
Como imprimir a localização completa sem parar o programa?

Quando você não quer parar o seu programa com um erro, você precisa lidar com esse erro com uma tentativa / exceto:

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

Para extrair o traceback completo, vamos usar o módulo traceback da biblioteca padrão:

import traceback
E criar um stacktrace decentemente complicado para demonstrar que temos o stacktrace completo:
def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Impressão

A imprimir a traceback completo, usar o método traceback.print_exc:

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

Que 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!

É melhor do que imprimir, registar:

No entanto, uma boa prática é ter um logger configurado para o seu módulo. Ele conhecerá o nome do módulo e será capaz de mudar os níveis (entre outros atributos, como manipuladores)

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

Nesse caso, vais querer a função logger.exception em vez disso:

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

Que registos:

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 talvez só queiras a corda, nesse caso ... , você vai querer a função traceback.format_exc em vez disso:
try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

Que registos:

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!

Conclusão

E para todas as três opções, vemos que temos a mesma saída que quando temos um erro:

>>> 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!
 59
Author: Aaron Hall, 2016-03-23 01:50:19

Para obter o preciso stack trace, como uma string, que teria sido levantado se nenhuma tentativa / excepto se houvesse para pisar sobre ele, basta colocar isto no bloco excepto que apanha a excepção ofensiva.

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

Aqui está como usá-lo (assumindo que flaky_func está definido, e log chama o seu sistema de Registo favorito):

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)
É uma boa idéia pegar e re-levantar {[[4]}, para que você ainda possa matar o programa usando Ctrl-C. loging está fora do escopo do pergunta, mas uma boa opção é registar . Documentação para os módulos etraceback .
 6
Author: Edward Newell, 2015-11-15 18:35:03

Terá de colocar a tentativa / excepto dentro do mais interior onde o erro possa ocorrer, ou seja

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

... e assim por diante

Em outras palavras, você vai precisar embrulhar declarações que podem falhar em tentativa/exceto o mais específico possível, no mais interior-loop possível.

 5
Author: Ivo van der Wijk, 2010-09-13 17:10:16

Para além da resposta de @Aaron Hall, se estiver a registar-se, mas não quiser usar {[[1]} (Dado que se regista no nível de erro), pode usar um nível mais baixo e passar exc_info=True. por exemplo

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)
 4
Author: Mark McDonald, 2018-04-24 03:19:02

Queres o módulo traceback. Ele vai deixar você imprimir pilha dumps como Python normalmente faz. Em particular, a função print_last irá imprimir a última excepção e um traço de pilha.

 2
Author: nmichaels, 2010-09-13 17:25:22