recent most last python traceback

most - traceback python 3



Obtener el rastreo completo (4)

Como respondió mechmind, el seguimiento de la pila consiste solo en cuadros entre el sitio donde se generó la excepción y el sitio del bloque try . Si necesita la traza de pila completa, aparentemente no tiene suerte.

Excepto que, obviamente, es posible extraer las entradas de la pila desde el nivel superior al marco actual: traceback.extract_stack maneja bien. El problema es que la información obtenida por traceback.extract_stack proviene de la inspección directa de los marcos de la pila sin crear un objeto de rastreo en ningún punto, y la API de logging requiere que un objeto de rastreo afecte la salida de rastreo.

Afortunadamente, el logging no requiere un objeto de rastreo real , requiere un objeto que pueda pasar a las rutinas de formato del módulo de traceback . traceback tampoco le importa, solo usa dos atributos de la traza de retorno, el marco y el número de línea. Por lo tanto, debería ser posible crear una lista enlazada de objetos falsos de rastreo de tipo pato y pasarla como el rastreo.

import sys class FauxTb(object): def __init__(self, tb_frame, tb_lineno, tb_next): self.tb_frame = tb_frame self.tb_lineno = tb_lineno self.tb_next = tb_next def current_stack(skip=0): try: 1/0 except ZeroDivisionError: f = sys.exc_info()[2].tb_frame for i in xrange(skip + 2): f = f.f_back lst = [] while f is not None: lst.append((f, f.f_lineno)) f = f.f_back return lst def extend_traceback(tb, stack): """Extend traceback with stack info.""" head = tb for tb_frame, tb_lineno in stack: head = FauxTb(tb_frame, tb_lineno, head) return head def full_exc_info(): """Like sys.exc_info, but includes the full traceback.""" t, v, tb = sys.exc_info() full_tb = extend_traceback(tb, current_stack(1)) return t, v, full_tb

Con estas funciones implementadas, su código solo requiere una modificación trivial:

import logging def func(): try: raise Exception(''Dummy'') except: logging.error("Something awful happened!", exc_info=full_exc_info()) def func2(): func() func2()

... para dar el resultado esperado:

ERROR:root:Something awful happened! Traceback (most recent call last): File "a.py", line 52, in <module> func2() File "a.py", line 49, in func2 func() File "a.py", line 43, in func raise Exception(''Dummy'') Exception: Dummy

Tenga en cuenta que los objetos faux-traceback son totalmente utilizables para la introspección (mostrar variables locales o como argumento para pdb.post_mortem() porque contienen referencias a marcos de pila reales.

¿Cómo puedo obtener un seguimiento completo en el siguiente caso, incluidas las llamadas de funciones func2 y func ?

import traceback def func(): try: raise Exception(''Dummy'') except: traceback.print_exc() def func2(): func() func2()

Cuando ejecuto esto, me sale:

Traceback (most recent call last): File "test.py", line 5, in func raise Exception(''Dummy'') Exception: Dummy

traceback.format_stack() no es lo que quiero, ya que necesito que el objeto de traceback se pase a un módulo de terceros.

Estoy particularmente interesado en este caso:

import logging def func(): try: raise Exception(''Dummy'') except: logging.exception("Something awful happened!") def func2(): func() func2()

En este caso estoy recibiendo:

ERROR:root:Something awful happened! Traceback (most recent call last): File "test.py", line 9, in func raise Exception(''Dummy'') Exception: Dummy


El seguimiento de la pila se recopila cuando la excepción aumenta. Así que debes imprimir el rastreo en la parte superior de la pila deseada:

import traceback def func(): raise Exception(''Dummy'') def func2(): func() try: func2() except: traceback.print_exc()


Hay algo más de información que se puede extraer del rastreo, y a veces prefiero una información más "clara" y más lógica en lugar del blob multilínea con archivos, números de línea y fragmentos de código dado por el rastreo. Preferiblemente una línea debe decir todo lo esencial.

Para lograr esto utilizo la siguiente función:

def raising_code_info(): code_info = '''' try: frames = inspect.trace() if(len(frames)): full_method_name = frames[0][4][0].rstrip(''/n/r'').strip() line_number = frames[1][2] module_name = frames[0][0].f_globals[''__name__''] if(module_name == ''__main__''): module_name = os.path.basename(sys.argv[0]).replace(''.py'','''') class_name = '''' obj_name_dot_method = full_method_name.split(''.'', 1) if len(obj_name_dot_method) > 1: obj_name, full_method_name = obj_name_dot_method try: class_name = frames[0][0].f_locals[obj_name].__class__.__name__ except: pass method_name = module_name + ''.'' if len(class_name) > 0: method_name += class_name + ''.'' method_name += full_method_name code_info = ''%s, line %d'' % (method_name, line_number) finally: del frames sys.exc_clear() return code_info

Da . y número de línea, por ejemplo:

(ejemplo de nombre del módulo: test.py):

(line 73:) def function1(): print 1/0 class AClass(object): def method2(self): a = [] a[3] = 1 def try_it_out(): # try it with a function try: function1() except Exception, what: print ''%s: /"%s/"'' % (raising_code_info(), what) # try it with a method try: my_obj_name = AClass() my_obj_name.method2() except Exception, what: print ''%s: /"%s/"'' % (raising_code_info(), what) if __name__ == ''__main__'': try_it_out() test.function1(), line 75: "integer division or modulo by zero" test.AClass.method2(), line 80: "list assignment index out of range"

Lo que podría ser un poco más ordenado en algunos casos de uso.


He escrito un módulo que escribe un rastreo más completo.

El módulo está here documentación es docs

(También puede obtener el módulo de pypi

sudo pip install pd

)

Para atrapar y pring excepciones haga lo siguiente:

import pd try: <python code> except BaseException: pd.print_exception_ex( follow_objects = 1 )

La traza de pila se parece a esta aquí:

Exception: got it #1 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 1) at t test_pd.py:29 Calls next frame at: raise Exception(''got it'') at: test_pd.py:29 #2 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 2) at test_pd.py:28 Calls next frame at: self.kuku2( depth - 1 ) at: test_pd.py:28 #3 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 3) at test_pd.py:28 Calls next frame at: self.kuku2( depth - 1 ) at: test_pd.py:28 #4 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 4) at test_pd.py:28 Calls next frame at: self.kuku2( depth - 1 ) at: test_pd.py:28 #5 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 5) at test_pd.py:28 Calls next frame at: self.kuku2( depth - 1 ) at: test_pd.py:28 #6 def kuku2(self = {''a'': 42, ''b'': [1, 2, 3, 4]}, depth = 6) at test_pd.py:28 Calls next frame at: self.kuku2( depth - 1 ) at: test_pd.py:28 #7 def main() at test_pd.py:44 Local variables: n = {''a'': 42, ''b'': [1, 2, 3, 4]} Calls next frame at: pd.print_exception_ex( follow_objects = 1 ) at: test_pd.py:44

follow_objects = 0 no imprimirá el contenido del objeto (con estructuras de datos complejas, follow_objects puede llevar mucho tiempo).