Estoy escribiendo un programa que analiza 10 sitios web, localiza archivos de datos, guarda los archivos y luego los analiza para crear datos que puedan usarse fácilmente en la biblioteca NumPy. Hay un montón de errores que este archivo encuentra a través de enlaces incorrectos, XML mal formado, entradas faltantes y otras cosas que aún no he categorizado. Inicialmente hice este programa para manejar errores como este:
try:
do_stuff()
except:
pass
Pero ahora quiero registrar errores:
try:
do_stuff()
except Exception, err:
print Exception, err
Tenga en cuenta que esto se imprime en un archivo de registro para su posterior revisión. Esto generalmente imprime datos muy inútiles. Lo que quiero es imprimir exactamente las mismas líneas impresas cuando el error se dispara sin el intento, excepto interceptar la excepción, pero no quiero que detenga mi programa ya que está anidado en una serie de bucles for que me gustaría ver hasta el final.
fuente
print(sys.exc_info()[0]
impresiones<class 'Exception'>
.Si está depurando y solo quiere ver el seguimiento de la pila actual, simplemente puede llamar:
traceback.print_stack()
No es necesario generar manualmente una excepción solo para atraparla nuevamente.
fuente
Cuando no desee detener su programa por un error, debe manejar ese error con un intento / excepto:
Para extraer el rastreo completo, usaremos el
traceback
módulo de la biblioteca estándar:Y para crear un stacktrace decentemente complicado para demostrar que obtenemos el stacktrace completo:
Impresión
Para imprimir el rastreo completo, use el
traceback.print_exc
método:Que imprime:
Mejor que imprimir, iniciar sesión:
Sin embargo, una mejor práctica es tener un registrador configurado para su módulo. Conocerá el nombre del módulo y podrá cambiar los niveles (entre otros atributos, como los controladores)
En cuyo caso, querrá la
logger.exception
función en su lugar:Qué registros:
O tal vez solo desee la cadena, en cuyo caso, querrá la
traceback.format_exc
función en su lugar:Qué registros:
Conclusión
Y para las tres opciones, vemos que obtenemos el mismo resultado que cuando tenemos un error:
fuente
traceback.print_exc()
sólo devuelve la última llamada: ¿cómo tener éxito para devolver varios niveles de la pila (y posiblemente todos levele s?)raise
encadenamiento desnudo o de excepción, o estás ocultando el rastreo original? ver stackoverflow.com/questions/2052390/…En primer lugar, no hacer uso
print
s para el registro, hay astable, probada y bien pensado módulo stdlib de hacerlo:logging
. Definitivamente deberías usarlo en su lugar.En segundo lugar, no se sienta tentado a hacer un lío con herramientas no relacionadas cuando hay un enfoque nativo y simple. Aquí está:
Eso es. Ya terminaste.
Explicación para cualquiera que esté interesado en cómo funcionan las cosas bajo el capó
Lo
log.exception
que realmente está haciendo es solo una llamada alog.error
(es decir, registrar un evento con nivelERROR
) e imprimir el rastreo en ese momento.¿Por qué es mejor?
Bueno, aquí hay algunas consideraciones:
¿Por qué nadie debería usar
traceback
o llamar al registradorexc_info=True
o ensuciarse las manossys.exc_info
?Bueno, solo porque! Todos existen para diferentes propósitos. Por ejemplo,
traceback.print_exc
la salida es un poco diferente de las trazas producidas por el propio intérprete. Si lo usa, confundirá a cualquiera que lea sus registros, se golpeará la cabeza contra ellos.Pasar
exc_info=True
a las llamadas de registro es simplemente inapropiado. Pero es útil cuando se detectan errores recuperables y desea registrarlos (usando, por ejemplo,INFO
nivel) con trazas, porquelog.exception
produce registros de solo un nivel -ERROR
.Y definitivamente deberías evitar jugar
sys.exc_info
tanto como puedas. Simplemente no es una interfaz pública, es interna, puede usarla si definitivamente sabe lo que está haciendo. No está destinado solo a imprimir excepciones.fuente
logging.exception()
. No es necesario crear una instancia de registro a menos que tenga requisitos especiales.Además de la respuesta de @Aaron Hall, si está iniciando sesión, pero no desea usar
logging.exception()
(ya que se registra en el nivel ERROR), puede usar un nivel inferior y pasarexc_info=True
. p.ejfuente
Para obtener el seguimiento preciso de la pila, como una cadena, que se habría elevado si no hubiera ningún intento / excepción para pasar por encima de él, simplemente colóquelo en el bloque except que atrapa la excepción ofensiva.
Aquí se explica cómo usarlo (suponiendo que
flaky_func
esté definido ylog
llame a su sistema de registro favorito):Es una buena idea atrapar y volver a subir
KeyboardInterrupt
s, para que aún pueda matar el programa usando Ctrl-C. El registro está fuera del alcance de la pregunta, pero una buena opción es el registro . Documentación para los módulos sys y traceback .fuente
desired_trace = traceback.format_exc()
. Pasarsys.exc_info()
como argumento nunca fue lo correcto, pero se ignora silenciosamente en Python 2, pero no en Python 3 (3.6.4 de todos modos).KeyboardInterrupt
no se deriva (directa o indirectamente) deException
. (Ambos se derivan deBaseException
). Esto significaexcept Exception:
que nunca atrapará aKeyboardInterrupt
, y por lo tanto,except KeyboardInterrupt: raise
es completamente innecesario.traceback.format_exc(sys.exc_info())
no funciona para mí con python 3.6.10Deberá poner el try / except dentro del bucle más interno donde puede ocurrir el error, es decir
... y así
En otras palabras, necesitará ajustar las declaraciones que pueden fallar en try / excepto lo más específico posible, en el bucle más interno posible.
fuente
Un comentario sobre los comentarios de esta respuesta :
print(traceback.format_exc())
hace un mejor trabajo para mí quetraceback.print_exc()
. Con este último, ahello
veces se "mezcla" extrañamente con el texto de rastreo, como si ambos quieren escribir en stdout o stderr al mismo tiempo, produciendo resultados extraños (al menos al construir desde el interior de un editor de texto y ver el resultado en el Panel "Resultados de compilación").Entonces uso:
fuente
No veo esto mencionado en ninguna de las otras respuestas. Si está pasando un objeto Exception por cualquier razón ...
En Python 3.5+ puede obtener un seguimiento de un objeto Exception utilizando traceback.TracebackException.from_exception () . Por ejemplo:
Sin embargo, el código anterior da como resultado:
Estos son solo dos niveles de la pila, a diferencia de lo que se habría impreso en la pantalla si la excepción se hubiera elevado
stack_lvl_2()
y no interceptado (descomente la# raise
línea).Según tengo entendido, eso se debe a que una excepción registra solo el nivel actual de la pila cuando se eleva,
stack_lvl_3()
en este caso. A medida que pasa de nuevo a través de la pila, se le agregan más niveles__traceback__
. Pero lo interceptamosstack_lvl_2()
, lo que significa que todo lo que consiguió registrar fueron los niveles 3 y 2. Para obtener el rastro completo tal como está impreso en stdout, tendríamos que atraparlo en el nivel más alto (¿más bajo?):Lo que resulta en:
Observe que la impresión de la pila es diferente, faltan la primera y la última línea. Porque es diferente
format()
.Interceptar la excepción lo más lejos posible del punto en el que se generó hace que el código sea más simple y al mismo tiempo proporciona más información.
fuente
Obtenga el rastreo completo como una cadena del objeto de excepción con
traceback.format_exception
Si solo tiene el objeto de excepción, puede obtener el rastreo como una cadena desde cualquier punto del código en Python 3 con:
Ejemplo completo:
Salida:
Documentación: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
Consulte también: Extraer información de rastreo de un objeto de excepción
Probado en Python 3.7.3.
fuente
Desea el módulo de rastreo . Le permitirá imprimir volcados de pila como Python normalmente lo hace. En particular, la función print_last imprimirá la última excepción y un seguimiento de la pila.
fuente
Si ya tiene un objeto Error y desea imprimir todo, debe hacer esta llamada un poco incómoda:
Así es,
print_exception
toma tres argumentos posicionales: el tipo de excepción, el objeto de excepción real y la propiedad de rastreo interno propia de la excepción.En python 3.5 o posterior, el
type(err)
es opcional ... pero es un argumento posicional, por lo que aún debe pasar explícitamente Ninguno en su lugar.No tengo idea de por qué todo esto no es solo
traceback.print_exception(err)
. Por qué alguna vez querrías imprimir un error, junto con un rastreo que no sea el que pertenece a ese error, me supera.fuente