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

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

try:
    do_stuff()
except:
    pass

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

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

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



답변

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

통지에 있음을하십시오 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!")


답변

traceback.format_exc()또는 sys.exc_info()만약 당신이 원하는 더 많은 정보를 얻을 것입니다.

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[2])


답변

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

traceback.print_stack()

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


답변

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

오류로 인해 프로그램을 중단하지 않으려면 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!


답변

먼저 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당신이 할 수 있는 한 많은 혼란을 피해야 합니다. 공용 인터페이스가 아니라 내부 인터페이스 입니다. 자신이하는 일을 확실히 알고 있다면 사용할 있습니다. 인쇄 예외만을위한 것은 아닙니다.


답변

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

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


답변

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

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 모듈에 대한 설명서