Estou escrevendo um programa que analisa 10 sites, localiza arquivos de dados, salva os arquivos e os analisa para criar dados que podem ser facilmente usados na biblioteca NumPy. Existem muitos erros que esse arquivo encontra por meio de links incorretos, XML mal formado, entradas ausentes 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 eu quero registrar erros:
try:
do_stuff()
except Exception, err:
print Exception, err
Observe que isso está sendo impresso em um arquivo de log para posterior revisão. Isso geralmente imprime dados muito inúteis. O que eu quero é imprimir exatamente as mesmas linhas impressas quando o erro for disparado sem a tentativa, exceto interceptar a exceção, mas não quero que ele interrompa meu programa, pois está aninhado em uma série de loops que gostaria de veja a conclusão.
fonte
print(sys.exc_info()[0]
impressões<class 'Exception'>
.Se você estiver depurando e quiser apenas ver o rastreamento da pilha atual, basta chamar:
traceback.print_stack()
Não há necessidade de criar manualmente uma exceção apenas para capturá-la novamente.
fonte
Quando você não deseja interromper seu programa com um erro, você precisa lidar com esse erro com uma tentativa / exceto:
Para extrair o rastreamento completo, usaremos o
traceback
módulo da biblioteca padrão:E para criar um stacktrace decentemente complicado para demonstrar que temos o stacktrace completo:
Impressão
Para imprimir o rastreamento completo, use o
traceback.print_exc
método:Que imprime:
Melhor do que imprimir, registrar:
No entanto, uma prática recomendada é ter um criador de logs configurado para o seu módulo. Ele saberá o nome do módulo e poderá alterar os níveis (entre outros atributos, como manipuladores)
Nesse caso, você desejará a
logger.exception
função:Quais logs:
Ou talvez você queira apenas a string; nesse caso, você desejará a
traceback.format_exc
função:Quais logs:
Conclusão
E para todas as três opções, vemos que obtemos a mesma saída de quando temos um erro:
fonte
traceback.print_exc()
retornos somente a última chamada: como você ter sucesso para retornar vários nível da pilha (e possivelmente todos levele s?)raise
encadeamento simples ou de exceção, ou está escondendo o rastreio original? veja stackoverflow.com/questions/2052390/…Primeiro, não use
print
s para registro, há astable, comprovada e bem pensado módulo stdlib de fazer isso:logging
. Você definitivamente deveria usá-lo.Segundo, não fique tentado a mexer com ferramentas não relacionadas quando houver uma abordagem simples e nativa. Aqui está:
É isso aí. Você terminou agora.
Explicação para quem estiver interessado em como as coisas funcionam sob o capô
log.exception
Na verdade, o que está fazendo é apenas uma chamada paralog.error
(ou seja, registrar evento com nívelERROR
) e imprimir o rastreamento depois.Por que é melhor?
Bem, aqui estão algumas considerações:
Por que ninguém deve usar
traceback
ou chamar o registradorexc_info=True
ou sujar as mãossys.exc_info
?Bem, só porque! Todos eles existem para diferentes propósitos. Por exemplo,
traceback.print_exc
a saída de é um pouco diferente dos rastreamentos produzidos pelo próprio intérprete. Se você usá-lo, confundirá qualquer um que ler seus registros, eles estarão batendo com a cabeça contra eles.Passar
exc_info=True
para registrar chamadas é apenas inapropriado. Porém , é útil ao capturar erros recuperáveis e você deseja registrá-los (usando, por exemplo,INFO
nível) com rastreamentos também, porquelog.exception
produz logs de apenas um nível -ERROR
.E você definitivamente deve evitar mexer com
sys.exc_info
o máximo que puder. Não é apenas uma interface pública, é uma interface interna - você pode usá-la se souber definitivamente o que está fazendo. Não se destina apenas a imprimir exceções.fonte
logging.exception()
. Não há necessidade de criar instância do log, a menos que você tenha requisitos especiais.Além da resposta do @Aaron Hall, se você estiver registrando, mas não quiser usá-
logging.exception()
lo (já que registra no nível ERROR), você pode usar um nível mais baixo e passarexc_info=True
. por exemplofonte
Para obter o rastreio preciso da pilha, como uma string, que teria sido aumentada se não houvesse tentativa / exceção, basta colocá-lo no bloco de exceção que captura a exceção incorreta.
Veja como usá-lo (supondo que
flaky_func
esteja definido elog
chame seu sistema de registro favorito):É uma boa ideia capturar e aumentar novamente
KeyboardInterrupt
s, para que você ainda possa matar o programa usando Ctrl-C. O log está fora do escopo da pergunta, mas uma boa opção é o log . Documentação para os módulos sys e traceback .fonte
desired_trace = traceback.format_exc()
. Passarsys.exc_info()
como o argumento nunca foi a coisa correta a se fazer, mas é ignorado silenciosamente no Python 2 - mas não no Python 3 (3.6.4 de qualquer maneira).KeyboardInterrupt
não é derivado (direta ou indiretamente) deException
. (Ambos são derivados deBaseException
.) Isso significaexcept Exception:
que nunca será capturado aKeyboardInterrupt
e, portanto,except KeyboardInterrupt: raise
é completamente desnecessário.traceback.format_exc(sys.exc_info())
não está funcionando para mim com python 3.6.10Você precisará colocar a tentativa / exceto dentro do loop mais interno onde o erro pode ocorrer, ou seja,
... e assim por diante
Em outras palavras, você precisará agrupar as instruções que podem falhar no try / exceto o mais específico possível, no loop mais interno possível.
fonte
Uma observação sobre os comentários desta resposta :
print(traceback.format_exc())
faz um trabalho melhor para mim do quetraceback.print_exc()
. Com o último, àshello
vezes é estranhamente "misturado" com o texto de rastreamento, como se ambos quisessem escrever para stdout ou stderr ao mesmo tempo, produzindo resultados estranhos (pelo menos ao construir de dentro de um editor de texto e visualizar a saída no Painel "Criar resultados").Então eu uso:
fonte
Não vejo isso mencionado em nenhuma das outras respostas. Se você estiver passando um objeto Exception por qualquer motivo ...
No Python 3.5+, é possível rastrear um objeto Exception usando traceback.TracebackException.from_exception () . Por exemplo:
No entanto, o código acima resulta em:
São apenas dois níveis da pilha, em oposição ao que seria impresso na tela se a exceção tivesse sido levantada
stack_lvl_2()
e não interceptada (remova o comentário da# raise
linha).Pelo que entendi, isso ocorre porque uma exceção registra apenas o nível atual da pilha quando é aumentada,
stack_lvl_3()
neste caso. À medida que passa pela pilha, mais níveis estão sendo adicionados a ela__traceback__
. Mas nós o interceptamosstack_lvl_2()
, o que significa que tudo o que foi registrado foi nos níveis 3 e 2. Para obter o rastreio completo impresso no stdout, teríamos que capturá-lo no nível mais alto (mais baixo?):O que resulta em:
Observe que a impressão da pilha é diferente, faltam a primeira e a última linhas. Porque é diferente
format()
.Interceptar a exceção o mais longe possível do ponto em que foi gerada facilita o código mais simples e também fornece mais informações.
fonte
Obtenha o rastreamento completo como uma sequência do objeto de exceção com
traceback.format_exception
Se você tiver apenas o objeto de exceção, poderá obter o traceback como uma string a partir de qualquer ponto do código no Python 3 com:
Exemplo completo:
Resultado:
Documentação: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
Consulte também: Extrair informações de rastreamento de um objeto de exceção
Testado em Python 3.7.3.
fonte
Você quer o módulo de rastreamento . Isso permitirá que você imprima dumps de pilha como o Python normalmente faz. Em particular, a função print_last imprimirá a última exceção e um rastreamento de pilha.
fonte
Se você já possui um objeto Error e deseja imprimir a coisa toda, precisa fazer esta chamada um pouco estranha:
Isso mesmo,
print_exception
leva três argumentos posicionais: O tipo da exceção, o objeto de exceção real e a propriedade traceback interna da própria exceção.No python 3.5 ou posterior, o
type(err)
é opcional ... mas é um argumento posicional, portanto, você ainda precisa passar explicitamente o None em seu lugar.Não tenho ideia de por que tudo isso não é apenas
traceback.print_exception(err)
. Por que você desejaria imprimir um erro, juntamente com um rastreio diferente daquele que pertence a esse erro, está além de mim.fonte