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


423

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

예외가 발생할 수있는 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이란 무엇 인가?

답변:


615

traceback모듈, 특히 format_exc()기능을 참조하십시오 . 이곳까지 .

import traceback

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

2
이것은 마지막 오류에서만 작동합니까? 다른 코드 비트로 오류를 전달하기 시작하면 어떻게됩니까? log_error(err)함수를 작성 중 입니다.
AnnanFay

잡히고 처리 된 오류와 함께 작동합니다.
kindall

74

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

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!

1
파이썬 3을 사용할 때 이것이 가장 좋은 방법입니까 (예 : 아래 답변 중 일부와 비교)?
Yunti

1
내가 믿는 @Yunti이 API는 파이썬 2와 3에서 일관하고있다
아론 홀

이 답변의 포맷은 메타에 논의되었다 : meta.stackoverflow.com/questions/386477/...를 .
Lundin

다음으로 수정 사항을 보냈지 만 익명으로 표시되도록 로그인하지 않았습니다. except Exception as e: logger.exception("<<clearly and distinctly describe what failed here>>", exc_info=e)
arntg

@arntg 도와 주셔서 감사합니다.하지만 수정 사항은 해로운 변화입니다. 앞으로 사용하려는 API를 완전히 이해하려면 앞으로 더 조심하십시오. 이 경우, 상기 exc_info(가) 반면 인수는 "예외 튜플을"기대 error의 인스턴스 Exception오브젝트 (또는 서브 클래스)을 변경할 필요가 없다 error하려면 e.
Aaron Hall

39

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


1
좋은 OO 스타일이 아니며 전역 변수를 사용하는 sys.exc_info ()보다 낫습니다.
WeiChing 林 煒 清

이것은 당신이했던 것처럼 예외 객체의 추적을 얻는 방법을 구체적으로 묻는다 : stackoverflow.com/questions/11414894/...
치로 틸리가郝海东冠状病六四事件法轮功

이 간단한 Python3 방법은 사용하지 않고있다 .__traceback__type참조 stackoverflow.com/a/58764987/5717886을
don_vanchos

34
>>> 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']

9

사용하는 사람들을 위해 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

읽을 수없는 복잡한 코드처럼 보입니다. 에서 파이썬 3.5 보다 우아하고 간단한 방법이있다 : stackoverflow.com/a/58764987/5717886
don_vanchos

6

내장 파이썬 모듈 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

5

예외가 처리되지 않을 때 동일한 정보를 얻으려면 다음과 같이 할 수 있습니다. 수행 import traceback다음과 :

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

Python 3.7을 사용하고 있습니다.


3

들어 파이썬 3.5 :

따라서 다른 예외와 마찬가지로 예외에서 스택 추적을 얻을 수 있습니다. 사용 traceback.TracebackException(단지 대체 그것을 위해 ex당신 제외) :

print("".join(traceback.TracebackException.from_exception(ex).format())

이를위한 확장 된 예제 및 기타 기능 :

import traceback

try:
    1/0
except Exception as ex:
    print("".join(traceback.TracebackException.from_exception(ex).format()) == traceback.format_exc() == "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))) # This is True !!
    print("".join(traceback.TracebackException.from_exception(ex).format()))

출력은 다음과 같습니다.

True
Traceback (most recent call last):
  File "untidsfsdfsdftled.py", line 29, in <module>
    1/0
ZeroDivisionError: division by zero

1

내 2 센트 :

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

1

파이썬에서 오류가 발생했을 때 예외 및 스택 추적 메시지를 정확하게 표시하는 것이 목표라면, 파이썬 2 + 3에서 다음이 작동합니다.

import sys, traceback


def format_stacktrace():
    parts = ["Traceback (most recent call last):\n"]
    parts.extend(traceback.format_stack(limit=25)[:-2])
    parts.extend(traceback.format_exception(*sys.exc_info())[1:])
    return "".join(parts)

# EXAMPLE BELOW...

def a():
    b()


def b():
    c()


def c():
    d()


def d():
    assert False, "Noooh don't do it."


print("THIS IS THE FORMATTED STRING")
print("============================\n")

try:
    a()
except:
    stacktrace = format_stacktrace()
    print(stacktrace)

print("THIS IS HOW PYTHON DOES IT")
print("==========================\n")
a()

format_stacktrace()스택에서 마지막 호출을 제거 하고 나머지를 결합하여 작동합니다. 실행될 때 위 예제는 다음과 같은 출력을 제공합니다.

THIS IS THE FORMATTED STRING
============================

Traceback (most recent call last):
  File "test.py", line 31, in <module>
    a()
  File "test.py", line 12, in a
    b()
  File "test.py", line 16, in b
    c()
  File "test.py", line 20, in c
    d()
  File "test.py", line 24, in d
    assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.

THIS IS HOW PYTHON DOES IT
==========================

Traceback (most recent call last):
  File "test.py", line 38, in <module>
    a()
  File "test.py", line 12, in a
    b()
  File "test.py", line 16, in b
    c()
  File "test.py", line 20, in c
    d()
  File "test.py", line 24, in d
    assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.

0

다음 도우미 클래스를 정의했습니다.

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));

(배경 : 나는 때문에 사용하는 frustraded 된 Promise과의 함께 Exception불행하게도 다른 장소에서 on_rejected 핸들러에 한 곳에서 발행되는 예외를 전달 S, 따라서이 원래 위치에서 역 추적을 얻을 어렵다)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.