[python] 예외를 일으킨 예외 설명 및 스택 추적을 모두 문자열로 가져옵니다.

파이썬에서 스택 추적 및 예외에 대한 많은 게시물을 보았습니다. 그러나 내가 필요한 것을 찾지 못했습니다.

예외가 발생할 수있는 Python 2.7 코드 덩어리가 있습니다. 나는 그것을 잡아서 전체 설명과 오류를 일으킨 스택 추적을 문자열에 할당하고 싶습니다 (콘솔에서 볼 때 사용하는 모든 것). GUI의 텍스트 상자에 인쇄하려면이 문자열이 필요합니다.

이 같은:

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


답변

전체 스택 추적을 얻는 방법을 보여주기 위해 상당히 복잡한 스택 추적을 만들어 봅시다.

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

def do_something_that_might_error():
    raise_error()

전체 스택 추적 로깅

모범 사례는 모듈에 로거를 설정하는 것입니다. 모듈의 이름을 알고 레벨을 변경할 수 있습니다 (핸들러와 같은 다른 속성 중에서)

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!


답변

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__속성 덕분에 ) 추가 처리를 위해 다른 함수에 대한 인수로 더 쉽게 전달 될 수 있다는 것입니다.


답변

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

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


답변

내장 파이썬 모듈 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을 사용하고 있습니다.