프로그램을 중단하지 않고 전체 역 추적을 인쇄하는 방법은 무엇입니까?


779

10 개의 웹 사이트를 구문 분석하고 데이터 파일을 찾은 다음 파일을 저장 한 다음 구문 분석하여 NumPy 라이브러리에서 쉽게 사용할 수있는 데이터를 만드는 프로그램을 작성 중입니다. 있다 이 파일 만남 내가 분류 아직했습니다 잘못된 링크, 제대로 형성된 XML, 누락 된 항목 및 기타 물건을 통해 오류가. 처음에 다음과 같은 오류를 처리하기 위해이 프로그램을 만들었습니다.

try:
    do_stuff()
except:
    pass

그러나 이제 오류를 기록하고 싶습니다.

try:
    do_stuff()
except Exception, err:
    print Exception, err

나중에 검토 할 수 있도록 로그 파일로 인쇄하고 있습니다. 이것은 일반적으로 매우 쓸모없는 데이터를 인쇄합니다. 내가 원하는 것은 예외를 방해하지 않고 try-except없이 오류가 발생할 때 인쇄 된 것과 동일한 줄을 인쇄하는 것입니다.하지만 일련의 for 루프에 중첩되어 있기 때문에 프로그램을 중단하고 싶지 않습니다. 완료를 참조하십시오.

답변:


583

다른 답변은 이미 역 추적을 지적했습니다. 모듈을 .

통지에 있음을하십시오 print_exc, 어떤 코너의 경우에, 당신은 당신이 무엇을 기대 얻을하지 않습니다. Python 2.x에서 :

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

... 마지막 예외 의 역 추적을 표시합니다 :

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

원래 역 추적에 실제로 액세스해야하는 경우 한 가지 해결책은 로컬 변수에서 반환 된 예외 정보 를 캐시하고 exc_info다음을 사용하여 표시하는 것입니다 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

생산 :

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

이로 인한 함정은 거의 없습니다.

  • 의 문서에서 sys_info:

    예외를 처리하는 함수에서 지역 변수에 역 추적 반환 값을 할당하면 순환 참조 가 발생합니다 . 이렇게하면 동일한 함수의 로컬 변수 또는 역 추적에 의해 참조 된 항목이 가비지 수집되지 않습니다. [...] 역 추적이 필요한 경우 사용 후 삭제해야합니다 (try ... finally 문으로 가장 잘 수행됨).

  • 그러나 같은 문서에서 :

    Python 2.2부터는 가비지 콜렉션이 사용 가능하고 도달 할 수 없을 때 이러한주기가 자동으로 회수 되지만주기 작성을 피하는 것이 더 효율적입니다.


반면에, 예외 와 관련된 역 추적에 액세스 할 수있게함으로써 Python 3은 덜 놀라운 결과를 낳습니다.

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

...가 표시됩니다 :

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")


258

디버깅 중이고 현재 스택 추적을 보려면 다음을 호출하면됩니다.

traceback.print_stack()

예외를 다시 잡기 위해 수동으로 예외를 제기 할 필요는 없습니다.


9
역 추적 모듈은 정확히 그렇게합니다. 예외를 발생시키고 잡아냅니다.
pppery

3
출력은 기본적으로 BTW로 STDERR로갑니다. 다른 곳으로 리디렉션되어 내 로그에 표시되지 않았습니다.
mpen

101

프로그램을 중단하지 않고 전체 역 추적을 인쇄하는 방법은 무엇입니까?

오류로 인해 프로그램을 중단하지 않으려면 try / except를 사용하여 해당 오류를 처리해야합니다.

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

전체 역 추적을 추출하기 위해 traceback표준 라이브러리에서 모듈을 사용합니다 .

import traceback

그리고 전체 스택 트레이스를 얻는 것을 보여주기 위해 상당히 복잡한 스택 트레이스를 만들려면 다음을 수행하십시오.

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

def do_something_that_might_error():
    raise_error()

인쇄

전체 역 추적 을 인쇄 하려면 다음 traceback.print_exc방법을 사용하십시오 .

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

어떤 지문 :

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 logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

이 경우 logger.exception대신 함수가 필요합니다.

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!

또는 문자열을 원할 수도 있습니다.이 경우 traceback.format_exc대신 함수가 필요합니다.

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

어떤 로그 :

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!

결론

그리고 세 가지 옵션 모두에 대해 오류가있을 때와 동일한 결과를 얻습니다.

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

2
위에서 말한 것처럼 저에게도 traceback.print_exc()마지막 호출 만 반환합니다. 어떻게 여러 레벨의 스택 (그리고 아마도 모든 레벨을 반환합니까?)
herve-guerin

@geekobi 나는 당신이 여기에 무엇을 묻는 지 잘 모르겠습니다. 프로그램 / 인터프리터의 진입 점까지 역 추적을한다는 것을 보여줍니다. 당신은 무엇을 명확하지 않습니까?
Aaron Hall

1
@geekobi의 말은 catchback을 다시 올리면 traceback.print_exc ()는 원래 스택이 아닌 다시 올리는 스택을 반환합니다.
fizloki

@fizloki 어떻게 "후진"하고 있습니까? 베어 raise체인 또는 예외 체인 을 수행 중입니까 , 아니면 원래 역 추적을 숨기고 있습니까? 참조 stackoverflow.com/questions/2052390/...
아론 홀

21

먼저 print로깅을 위해 s를 사용 하지 마십시오 logging. stdlib 모듈은 다음과 같이 수행 할 수 있습니다. 당신은 확실히 해야한다 대신 사용.

둘째, 기본적이고 간단한 접근 방식이있을 때 관련이없는 도구 로 혼란 을 겪지 마십시오 . 여기있어:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

그게 다야. 이제 끝났습니다.

후드 아래에서 작동하는 방식에 관심이있는 사람을위한 설명

무엇 log.exception실제로하는 일은 단지에 대한 호출입니다 log.error(이다, 레벨 로그 이벤트 ERROR) 다음 역 추적 인쇄 할 수 있습니다.

왜 더 낫습니까?

여기 몇 가지 고려 사항이 있습니다.

  • 그것은 옳습니다 .
  • 그것은 간단하다.
  • 간단하다.

아무도 traceback로거를 사용 하거나 전화를 걸 exc_info=True거나 손을 더럽 히지 않아야하는 이유는 무엇 sys.exc_info입니까?

글쎄, 그냥! 그것들은 모두 다른 목적으로 존재합니다. 예를 들어 traceback.print_exc의 출력은 인터프리터 자체에서 생성 한 추적과 약간 다릅니다. 당신이 그것을 사용한다면, 당신은 당신의 로그를 읽는 사람을 혼란스럽게 할 것이고, 그들은 머리에 대고 머리를 부딪 칠 것입니다.

exc_info=True통화 기록에 전달 하는 것은 부적절합니다. 그러나 복구 가능한 오류를 포착 할 때 유용 하며 한 수준의 로그 만 생성 INFO하기 때문에 추적과 함께 오류를 기록 (예 : 레벨 사용)하려는 경우에도 유용합니다.log.exceptionERROR .

그리고 당신은 확실히 sys.exc_info당신이 할 수 있는 한 많은 혼란을 피해야 합니다. 공용 인터페이스가 아니라 내부 인터페이스 입니다. 자신이하는 일을 확실히 알고 있다면 사용할 있습니다. 인쇄 예외만을위한 것은 아닙니다.


4
또한 그대로 작동하지 않습니다. 그렇지 않습니다. 나는 지금 끝나지 않았습니다 :이 답변은 시간을 낭비합니다.
A. Rager

나는 또한 당신이 할 수 있다고 덧붙일 것 logging.exception()입니다. 특별한 요구 사항이 없으면 로그 인스턴스를 만들 필요가 없습니다.
Shital Shah

9

@Aaron Hall의 답변 외에도 로깅하고 있지만 사용하지 않으려는 경우 logging.exception()(오류 수준에서 로깅하기 때문에) 더 낮은 수준을 사용하고 전달할 수 exc_info=True있습니다. 예 :

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)

7

얻으려면 정확한 스택 추적을 문자열로, 그 위에 단계가이었다 제외하고는 어떤 시도는 /, 단순히 블록이 캐치를 일으키는 예외를 제외하고는이를 배치하지 않는 경우 제기되고있다.

desired_trace = traceback.format_exc(sys.exc_info())

사용 방법은 다음과 같습니다 (가정 flaky_func이 정의되어 log선호하는 로깅 시스템을 호출 함).

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

KeyboardInterruptCtrl-C를 사용하여 여전히 프로그램을 종료 할 수 있도록 s 를 잡아서 다시 올리는 것이 좋습니다 . 로깅은 질문의 범위를 벗어 났지만 logging을 사용 하는 것이 좋습니다 . systraceback 모듈에 대한 설명서


4
이것은 Python 3에서 작동하지 않으며로 변경해야 desired_trace = traceback.format_exc()합니다. sys.exc_info()인수로서 전달 하는 것은 결코 올바른 일이 아니지만 Python 2에서는 자동으로 무시되지만 Python 3에서는 자동으로 무시되지 않습니다 (3.6.4).
martineau

2
KeyboardInterrupt에서 (직접 또는 간접적으로) 파생되지 않았습니다 Exception. (모두에서 파생됩니다 BaseException.) 이것은 except Exception:결코을 잡을 KeyboardInterrupt수 없으므로 except KeyboardInterrupt: raise완전히 불필요합니다.
AJNeufeld

traceback.format_exc(sys.exc_info())하지 파이썬 3.6.10 나를 위해 일
남 G VU

6

오류가 발생할 수있는 가장 내부 루프 안에 try / except를 넣어야합니다.

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... 등등

다시 말해, 가능한 가장 구체적인 내부 루프에서 시도 / 제외에 실패 할 수있는 명령문을 랩핑해야합니다.


6

이 답변 의 의견에 대한 언급 : print(traceback.format_exc())보다 나에게 더 나은 일을합니다 traceback.print_exc(). 후자 hello는 stdout 또는 stderr에 동시에 쓰고 싶거나 이상한 출력을 생성하는 것처럼 (적어도 텍스트 편집기 내부에서 빌드하고 출력을 볼 때) 트레이스 백 텍스트와 이상하게 혼합됩니다. "빌드 결과"패널).

역 추적 (가장 최근 호출) :
파일 "C : \ Users \ User \ Desktop \ test.py", 7 행,
지옥 do_stuff ()
파일 "C : \ Users \ User \ Desktop \ test.py", 4 행 , do_stuff에서
1/0
ZeroDivisionError : 0으로 정수 나눗셈 모듈러스
O
[0.1 초에 완성]

그래서 나는 사용합니다 :

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

5

나는 다른 답변에서 언급되지 않았습니다. 어떤 이유로 든 Exception 객체를 전달하는 경우 ...

Python 3.5 이상에서는 traceback.TracebackException.from_exception ()을 사용하여 Exception 객체에서 추적을 얻을 수 있습니다 . 예를 들면 다음과 같습니다.

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e


def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

그러나 위 코드의 결과는 다음과 같습니다.

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

이것은 예외가 제기되고 stack_lvl_2()가로 채지 않은 경우 화면에 인쇄 된 것과 반대로 스택의 두 가지 수준에 불과 합니다.# raise 줄 ).

내가 이해하는 것처럼, 예외가 발생하면 예외가 스택의 현재 수준 ( stack_lvl_3()이 경우) 만 기록하기 때문 입니다. 스택을 통해 다시 전달되면 더 많은 레벨이에 추가됩니다 __traceback__. 그러나 우리는 그것을 가로 막았습니다 stack_lvl_2(). 즉, 기록해야 할 모든 것은 레벨 3과 2입니다.

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    stack_lvl_3()


def stack_lvl_1():
    stack_lvl_2()


try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

결과 :

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

스택 인쇄가 다르고 첫 번째와 마지막 행이 누락되었습니다. 왜냐하면 다른 것format() 입니다.

가능한 한 발생 된 지점에서 멀리 떨어진 예외를 가로 채면 더 간단한 정보를 제공하면서 코드가 단순 해집니다.


이것은 이전 방법보다 훨씬 낫지 만 스택 추적을 인쇄하는 것만으로도 엄청나게 복잡합니다. Java는 코드 FGS를 덜 사용합니다.
elhefe

3

역 추적 모듈을 원합니다 . 일반적으로 파이썬처럼 스택 덤프를 인쇄 할 수 있습니다. 특히 print_last 함수는 마지막 예외와 스택 추적을 인쇄합니다.


3

예외 객체에서 문자열로 전체 역 추적을 가져옵니다. traceback.format_exception

예외 객체 만 가지고 있다면 파이썬 3의 코드 포인트에서 다음과 같이 문자열로 역 추적을 얻을 수 있습니다.

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

전체 예 :

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

산출:

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

설명서 : https://docs.python.org/3.7/library/traceback.html#traceback.format_exception

참조 : 예외 객체에서 역 추적 정보 추출

파이썬 3.7.3에서 테스트되었습니다.


2

Error 객체가 이미 있고 모든 것을 인쇄하려면 다음과 같이 약간 어색한 호출을해야합니다.

import traceback
traceback.print_exception(type(err), err, err.__traceback__)

그렇습니다, 3print_exception 이 걸립니다 위치 인수 : 예외, 실제 예외 객체, 그리고 예외의 자신의 내부 추적 속성의 유형입니다.

파이썬 3.5 이상에서는 type(err)선택 사항입니다 ...하지만 위치 인수이므로 여전히 명시 적으로 None을 전달해야합니다.

traceback.print_exception(None, err, err.__traceback__)

왜이 모든 것이 단순한 것이 아닌지 모르겠습니다 traceback.print_exception(err) . 왜 그 에러에 속하지 않은 트레이스 백과 함께 에러를 출력하고 싶습니까?

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