Получите описание исключений и трассировку стека, что вызвало исключение, все как строка

StackOverflow https://stackoverflow.com/questions/4564559

Вопрос

Я видел много постов о трассировке стека и исключениях в Python. Но не нашел то, что мне нужно.

У меня есть кусок кода Python 2.7, который может поднять исключение. Я хотел бы поймать его и назначить нить Его полное описание и трассировка стека, которая вызвала ошибку (просто все, что мы используем, чтобы увидеть на консоли). Мне нужна эта строка, чтобы распечатать ее в текстовое поле в графическом интерфейсе.

Что-то вроде этого:

try:
    method_that_can_raise_an_exception(params)
except Exception as e:
    print_to_textbox(complete_exception_description(e))

Проблема в: Какая функция complete_exception_description?

Это было полезно?

Решение

Увидеть traceback модуль, в частности format_exc() функция Здесь.

import traceback

try:
    raise ValueError
except ValueError:
    tb = traceback.format_exc()
else:
    tb = "No error"
finally:
    print tb

Другие советы

Давайте создадим прилично сложную Stacktrace, чтобы продемонстрировать, что мы получим полную Stacktrace:

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

Регистрировать полную Stacktrace

Лучшая практика - настроить регистратор для вашего модуля. Он будет знать название модуля и сможет изменить уровни (среди других атрибутов, таких как обработчики)

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

И мы можем использовать этот журнал, чтобы получить ошибку:

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

Что вводит:

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!

И поэтому мы получаем такой же вывод, что и когда у нас есть ошибка:

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

Получение только строки

Если вам действительно просто нужна строка, используйте traceback.format_exc Вместо этого функция, демонстрируя регистрацию строки здесь:

import traceback
try:
    do_something_that_might_error()
except Exception as error:
    just_the_string = traceback.format_exc()
    logger.debug(just_the_string)

Что вводит:

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!
>>> import sys
>>> import traceback
>>> try:
...   5 / 0
... except ZeroDivisionError as e:
...   type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
['  File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Ты используешь sys.exc_info () собирать информацию и функции в traceback модуль для форматирования его.Здесь некоторые примеры для его форматирования.

Вся строка исключений по адресу:

>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']

С Python 3 следующий код будет отформатировать Exception объект точно так же, как будет получено с помощью traceback.format_exc():

import traceback

try: 
    method_that_can_raise_an_exception(params)
except Exception as ex:
    print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))

Преимущество состоит в том, что только Exception Объект необходим (благодаря записанным __traceback__ атрибут) и, следовательно, может быть легче передавать в качестве аргумента другой функции для дальнейшей обработки.

Для тех, кто использует Python-3

С использованием traceback модуль и exception.__traceback__ Можно извлечь трейс стека следующим образом:

  • захватить Текущий стек-трейс с использованием traceback.extract_stack()
  • Удалите последние три элемента (так как это записи в стеке, которые привели меня к функции отладки)
  • добавить __traceback__ Из объекта исключения с помощью traceback.extract_tb()
  • форматируйте все, используя traceback.format_list()
import traceback
def exception_to_string(excp):
   stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__)  # add limit=?? 
   pretty = traceback.format_list(stack)
   return ''.join(pretty) + '\n  {} {}'.format(excp.__class__,excp)

Простая демонстрация:

def foo():
    try:
        something_invalid()
    except Exception as e:
        print(exception_to_string(e))

def bar():
    return foo()

Мы получаем следующий вывод, когда звоним bar():

  File "./test.py", line 57, in <module>
    bar()
  File "./test.py", line 55, in bar
    return foo()
  File "./test.py", line 50, in foo
    something_invalid()

  <class 'NameError'> name 'something_invalid' is not defined

Вы также можете рассмотреть возможность использования встроенного модуля Python, CGITB, чтобы получить некоторую действительно хорошую, хорошо отформатированную информацию об исключении, включая значения локальных переменных, контекст исходного кода, параметры функции и т. Д.

Например, для этого кода ...

import cgitb
cgitb.enable(format='text')

def func2(a, divisor):
    return a / divisor

def func1(a, b):
    c = b - 5
    return func2(a, c)

func1(1, 5)

Мы получаем этот вывод исключения ...

ZeroDivisionError
Python 3.4.2: C:\tools\python\python.exe
Tue Sep 22 15:29:33 2015

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred.

 c:\TEMP\cgittest2.py in <module>()
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
func1 = <function func1>

 c:\TEMP\cgittest2.py in func1(a=1, b=5)
    7 def func1(a, b):
    8   c = b - 5
    9   return func2(a, c)
   10
   11 func1(1, 5)
global func2 = <function func2>
a = 1
c = 0

 c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
    3
    4 def func2(a, divisor):
    5   return a / divisor
    6
    7 def func1(a, b):
a = 1
divisor = 0
ZeroDivisionError: division by zero
    __cause__ = None
    __class__ = <class 'ZeroDivisionError'>
    __context__ = None
    __delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
    __dict__ = {}
    __dir__ = <built-in method __dir__ of ZeroDivisionError object>
    __doc__ = 'Second argument to a division or modulo operation was zero.'
    __eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
    __format__ = <built-in method __format__ of ZeroDivisionError object>
    __ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
    __getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
    __gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
    __hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
    __init__ = <method-wrapper '__init__' of ZeroDivisionError object>
    __le__ = <method-wrapper '__le__' of ZeroDivisionError object>
    __lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
    __ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
    __new__ = <built-in method __new__ of type object>
    __reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
    __reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
    __repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
    __setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
    __setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
    __sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
    __str__ = <method-wrapper '__str__' of ZeroDivisionError object>
    __subclasshook__ = <built-in method __subclasshook__ of type object>
    __suppress_context__ = False
    __traceback__ = <traceback object>
    args = ('division by zero',)
    with_traceback = <built-in method with_traceback of ZeroDivisionError object>

The above is a description of an error in a Python program.  Here is
the original traceback:

Traceback (most recent call last):
  File "cgittest2.py", line 11, in <module>
    func1(1, 5)
  File "cgittest2.py", line 9, in func1
    return func2(a, c)
  File "cgittest2.py", line 5, in func2
    return a / divisor
ZeroDivisionError: division by zero

Если вы хотите получить ту же информацию, предоставленную, когда исключение не обработано, вы можете сделать что -то подобное. Делать import traceback а потом:

try:
    ...
except Exception as e:
    print(traceback.print_tb(e.__traceback__))

Я использую Python 3.7.

мои 2 центы:

import sys, traceback
try: 
  ...
except Exception, e:
  T, V, TB = sys.exc_info()
  print ''.join(traceback.format_exception(T,V,TB))

Я определил после Helper Class:

import traceback
class TracedExeptions(object):
    def __init__(self):
        pass
    def __enter__(self):
        pass

    def __exit__(self, etype, value, tb):
      if value :
        if not hasattr(value, 'traceString'):
          value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
        return False
      return True

Что я могу позже использовать так:

with TracedExeptions():
  #some-code-which-might-throw-any-exception

А позже может поглотить это так:

def log_err(ex):
  if hasattr(ex, 'traceString'):
    print("ERROR:{}".format(ex.traceString));
  else:
    print("ERROR:{}".format(ex));

(Фон: я был разочарован из -за использования PromiseS вместе с ExceptionS, который, к сожалению, передает исключения, поднятые в одном месте для обработчика on_rejected в другом месте, и, таким образом, трудно получить отслеживание от оригинального местоположения)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top