chriscauley
Quiero capturar y registrar excepciones sin salir, por ejemplo,
try:
do_stuff()
except Exception as err:
print(Exception, err)
# I want to print the entire traceback here,
# not just the exception name and details
Quiero imprimir exactamente el mismo resultado que se imprime cuando se genera la excepción sin que try/except intercepte la excepción, y lo hago no quiero que salga de mi programa.
Voltaje
traceback.format_exc()
o sys.exc_info()
dará más información si eso es lo que quieres.
import traceback
import sys
try:
do_stuff()
except Exception:
print(traceback.format_exc())
# or
print(sys.exc_info()[2])
-
print(sys.exc_info()[0]
huellas dactilares<class 'Exception'>
.– weberc2
28 de agosto de 2019 a las 15:52
-
no use exc… el rastreo contiene toda la información stackoverflow.com/questions/4564559/…
– droide192
8 sep 2019 a las 18:11
-
print(sys.exc_info()[2])
rendimientos<traceback object at 0x0000028A79E6B2C8>
.– Teepeemm
14 oct 2020 a las 14:23
-
print(traceback.format_exc())
es mejor quetraceback.print_tb(exc.__traceback__)
.print(sys.exc_info())
devuelve toda la tupla y parece(<class 'UnicodeDecodeError'>, UnicodeDecodeError('utf-8', b'\x81', 0, 1, 'invalid start byte'), <traceback object at 0x7f179d64ae00>)
Así que de hechotraceback.format_exc()
es realmente superior porque eso imprimeTraceback (most recent call last): File "<ipython-input-15-9e3d6e01ef04>", line 2, in <module> b"\x81".decode() UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 0: invalid start byte
– Marca
7 mayo 2021 a las 20:47
-
quita eso
exc_info()
No funciona.– usamec
2 de agosto de 2022 a las 12:26
Sylvain Leroux
Alguna otra respuesta ya ha señalado el rastrear módulo.
Tenga en cuenta que con print_exc
, en algunos casos de esquina, no obtendrá lo que esperaría. En Python 2.x:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
… mostrará el rastreo de la último excepción:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
Si realmente necesita acceder al original rastrear una solución es almacenar en caché el información de excepción como regresado de exc_info
en una variable local y mostrarlo usando 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
Productor:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
Sin embargo, algunas trampas con esto:
-
Del documento de
sys_info
:Asignar el valor de retorno de rastreo a una variable local en una función que está manejando una excepción causará una referencia circular. Esto evitará que cualquier elemento referenciado por una variable local en la misma función o por el rastreo sea recolectado como basura. […] Si necesita el rastreo, asegúrese de eliminarlo después de usarlo (es mejor hacerlo con un intento… finalmente declaración)
-
pero, del mismo documento:
A partir de Python 2.2, dichos ciclos se recuperan automáticamente cuando la recolección de basura está habilitada y se vuelven inalcanzables, pero sigue siendo más eficiente para evitar la creación de ciclos.
Por otro lado, al permitirle acceder al rastreo asociado con una excepción, Python 3 produce un resultado menos sorprendente:
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
… mostrará:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
dimo414
Si está depurando y solo quiere ver el seguimiento de la pila actual, simplemente puede llamar:
No es necesario generar manualmente una excepción solo para volver a detectarla.
-
El módulo de rastreo hace exactamente eso: genera y detecta una excepción.
– pimienta
7 de noviembre de 2015 a las 19:08
-
La salida va a STDERR por defecto, por cierto. No aparecía en mis registros porque estaba siendo redirigido a otro lugar.
– mpen
11 de diciembre de 2018 a las 0:18
-
@pppery No puedo verlo con python 3.8. Y la cosa con
try
ycatch
es que no muestra el rastreo completo, solo deraise
aexcept
.– x-yuri
25 de junio de 2020 a las 19:12
Rusia debe sacar a Putin
¿Cómo imprimir el rastreo completo sin detener el programa?
Cuando no desea detener su programa por un error, debe manejar ese error con un intento/excepto:
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
Para extraer el rastreo completo, usaremos el traceback
módulo de la biblioteca estándar:
import traceback
Y para crear un stacktrace decentemente complicado para demostrar que obtenemos el stacktrace completo:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
Impresión
A imprimir el rastreo completo, use el traceback.print_exc
método:
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!
Mejor que imprimir, iniciar sesión:
Sin embargo, una mejor práctica es tener un registrador configurado para su módulo. Sabrá el nombre del módulo y podrá cambiar los niveles (entre otros atributos, como los controladores)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
En cuyo caso, querrá el logger.exception
función en su lugar:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
Que registra:
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!
O tal vez solo quiera la cuerda, en cuyo caso, querrá la traceback.format_exc
función en su lugar:
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
Que registra:
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!
Conclusión
Y para las tres opciones, vemos que obtenemos el mismo resultado que cuando tenemos un error:
>>> 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!
cual usar
Las preocupaciones de rendimiento no son importantes aquí, ya que IO suele dominar. Preferiría, ya que hace precisamente lo que se solicita de una manera compatible con versiones posteriores:
logger.exception(error)
Los niveles de registro y las salidas se pueden ajustar, lo que facilita el apagado sin tocar el código. Y, por lo general, hacer lo que se necesita directamente es la forma más eficiente de hacerlo.
Antonio
Primero, no use print
s para el registro, existe un estable, probado y bien pensado stdlib
módulo para hacer eso: logging
. Tu definitivamente debería úsalo en su lugar.
En segundo lugar, no caiga en la tentación de hacer una desorden con herramientas no relacionadas cuando existe un enfoque nativo y simple. Aquí lo tienes:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
Eso es todo. Ya has terminado.
Explicación para cualquiera que esté interesado en cómo funcionan las cosas debajo del capó
Qué log.exception
lo que realmente está haciendo es solo una llamada a log.error
(es decir, evento de registro con nivel ERROR
) y imprima el rastreo entonces.
¿Por qué es mejor?
Bueno, aquí hay algunas consideraciones:
- es sólo bien;
- es sencillo;
- Es simple.
¿Por qué nadie debería usar traceback
o registrador de llamadas con exc_info=True
o ensuciarse las manos con sys.exc_info
?
Bueno, ¡solo porque sí! Todos ellos existen para diferentes propósitos. Por ejemplo, traceback.print_exc
La salida de es un poco diferente de los rastreos producidos por el propio intérprete. Si lo usa, confundirá a cualquiera que lea sus registros, se golpeará la cabeza contra ellos.
Paso exc_info=True
registrar llamadas es simplemente inapropiado. Peroes útil cuando detecta errores recuperables y desea registrarlos (utilizando, por ejemplo, INFO
nivel) con trazabilidades también, porque log.exception
produce registros de un solo nivel – ERROR
.
Y definitivamente deberías evitar jugar con sys.exc_info
tanto como puedas. Simplemente no es una interfaz pública, es una interfaz interna: usted poder utilícelo si definitivamente sabe lo que está haciendo. No está diseñado solo para imprimir excepciones.
-
Tampoco funciona como está. Eso no es todo. No he terminado ahora: esta respuesta solo hace perder el tiempo.
– A. Rager
27 de abril de 2019 a las 16:07
-
También agregaría que solo puedes hacer
logging.exception()
. No es necesario crear una instancia de registro a menos que tenga requisitos especiales.– Shital Shah
18 de mayo de 2019 a las 6:35
-
Encuentro esta respuesta un poco ridícula. Está lleno de “haz/no hagas esto solo porque sí” sin explicar por qué. Sus puntos en “¿por qué es mejor?” Prácticamente es todo decir lo mismo: “porque es”. Lo cual no encuentro útil. Al menos explicaste un poco.
– Romper
18 de diciembre de 2020 a las 1:28
-
Buena información (no sabía sobre
logging.exception
) pero un poco condescendiente. Creo que esto se debe a la barrera del idioma más que a una intención maliciosa.– rjh
5 sep 2021 a las 14:49
-
Lo que dijo este tipo. En mi empresa despediremos a cualquiera que inicie sesión utilizando la impresión. /s
– omni
14 de enero de 2022 a las 12:33
traceback.format_exception(exception_object)
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:
import traceback
''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
Ejemplo completo:
#!/usr/bin/env python3
import traceback
def f():
g()
def g():
raise Exception('asdf')
try:
g()
except Exception as e:
exc_obj = e
tb_str="".join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)
Producción:
Traceback (most recent call last):
File "./main.py", line 12, in <module>
g()
File "./main.py", line 9, in g
raise Exception('asdf')
Exception: asdf
Documentación: https://docs.python.org/3.9/library/traceback.html#traceback.format_exception
Ver también: Extraer información de rastreo de un objeto de excepción
Probado en Python 3.9
-
Tampoco funciona como está. Eso no es todo. No he terminado ahora: esta respuesta solo hace perder el tiempo.
– A. Rager
27 de abril de 2019 a las 16:07
-
También agregaría que solo puedes hacer
logging.exception()
. No es necesario crear una instancia de registro a menos que tenga requisitos especiales.– Shital Shah
18 de mayo de 2019 a las 6:35
-
Encuentro esta respuesta un poco ridícula. Está lleno de “haz/no hagas esto solo porque sí” sin explicar por qué. Sus puntos en “¿por qué es mejor?” Prácticamente es todo decir lo mismo: “porque es”. Lo cual no encuentro útil. Al menos explicaste un poco.
– Romper
18 de diciembre de 2020 a las 1:28
-
Buena información (no sabía sobre
logging.exception
) pero un poco condescendiente. Creo que esto se debe a la barrera del idioma más que a una intención maliciosa.– rjh
5 sep 2021 a las 14:49
-
Lo que dijo este tipo. En mi empresa despediremos a cualquiera que inicie sesión utilizando la impresión. /s
– omni
14 de enero de 2022 a las 12:33
Neurona
Además de la respuesta de Aaron Hall, si está iniciando sesión, pero no quiere usar logging.exception()
(dado que se registra en el nivel de ERROR), puede usar un nivel más bajo y pasar exc_info=True
. p.ej
try:
do_something_that_might_error()
except Exception:
logging.info('General exception noted.', exc_info=True)
-
Esto también es bueno cuando se trata de una falla detectada en el registro… es decir, cuando por alguna razón no ha podido crear un objeto registrador real.
– mike roedor
21 de diciembre de 2021 a las 17:09
No es una respuesta completa, pero es posible que alguien quiera saber que puede acceder a mucha información investigando
err.__traceback__
(al menos en Python 3.x)– Vito gentil
25 de febrero de 2021 a las 12:10
Parece que soy el único en el mundo que quiere imprimir la pila cuando no hay error (= solo para ver cómo llegué aquí en esta línea precisa (no es mi código, y es tan feo que no puedo entender cómo llegó aquí!)).
–Olivier Pons
2 de junio de 2021 a las 8:23
Para entender el verdadero Zen de Python, @PavelVlasov, también debes saber cuándo el Zen de Python no es Zen. Antes de la iluminación, siguiendo los rastros de la pila, después de la iluminación, siguiendo los rastros de la pila. Un día comprenderás y estarás en paz, saltamontes. No regreses a la corrupción de Java de donde viniste.
– NeilG
28 de abril a las 1:01