파이썬에서 포착되지 않은 예외 로깅


181

잡히지 않는 예외가 logging아닌 모듈을 통해 어떻게 출력 stderr됩니까?

이 작업을 수행하는 가장 좋은 방법은 다음과 같습니다.

try:
    raise Exception, 'Throwing a boring exception'
except Exception, e:
    logging.exception(e)

그러나 내 상황은 예외가 포착되지 않을 때마다 자동으로 호출 되면 정말 좋을logging.exception(...)입니다.



답변:


143

Ned가 지적했듯이 sys.excepthook예외가 발생하여 포착되지 않을 때마다 호출됩니다. 이것의 실질적인 의미는 코드에서 sys.excepthook원하는 것을 수행 하는 기본 동작을 무시할 수 있다는 것입니다 (사용 포함 logging.exception).

짚맨 예를 들면 :

>>> import sys
>>> def foo(exctype, value, tb):
...     print 'My Error Information'
...     print 'Type:', exctype
...     print 'Value:', value
...     print 'Traceback:', tb
... 

무시 sys.excepthook:

>>> sys.excepthook = foo

명백한 구문 오류를 커밋하고 (콜론 제외) 사용자 지정 오류 정보를 다시 가져옵니다.

>>> def bar(a, b)
My Error Information
Type: <type 'exceptions.SyntaxError'>
Value: invalid syntax (<stdin>, line 1)
Traceback: None

자세한 내용은 대한 sys.excepthook읽기, 워드 프로세서 .


4
@Codemonkey 예약 키워드가 아니며 기존 유형 이름입니다. typeIDE가 전역 숨기기에 대해 불평하지만 함수 인수로 사용할 수 있습니다 type( var self = this자바 스크립트에서 사용 하는 것과 유사 ). type함수 내부 의 객체 에 액세스 해야하는 경우가 아니라면 type_인수로 대신 사용할 수 있습니다 .
Ryan P

3
여기에서 "언제나" 라는 문구 는 오해의 소지가 있습니다. : " 예외가 발생하여 포착되지 않을 마다 "sys.excepthook이 호출 됩니다 " ... 프로그램에는 정확히 하나의"포착되지 않은 "예외 가있을 수 있습니다 . 또한 sys.excepthook예외가 발생하면 호출되지 않습니다. 포착되지 않은 예외로 인해 프로그램이 종료 될 때 호출되며, 이는 두 번 이상 발생할 수 없습니다.
Nawaz

2
@Nawaz : REPL에서 두 번 이상 발생할 수 있습니다.
jfs

2
@Nawaz 프로그램이 스레드를 사용하는 경우에도 여러 번 발생할 수 있습니다. 또한 예외로 인해 sys.excepthook
three_pineapples

1
위의 코드를 테스트하려는 사람은 함수를 테스트하는 동안 역 추적 오류를 생성해야합니다. SyntaxError는 sys.excepthook에 의해 처리되지 않습니다. 당신은 인쇄 (1/0)를 사용할 수 있으며, 이것은 당신이 재정의 sys.excepthook에 정의 된 함수를 호출된다
Parth Karia

177

다음은 몇 가지 다른 트릭을 포함하는 완전한 작은 예입니다.

import sys
import logging
logger = logging.getLogger(__name__)
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)

def handle_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_exception

if __name__ == "__main__":
    raise RuntimeError("Test unhandled")
  • Console python 프로그램이 Ctrl + C로 종료 될 수 있도록 KeyboardInterrupt를 무시하십시오.

  • 예외를 형식화하려면 파이썬의 로깅 모듈에 전적으로 의존하십시오.

  • 예제 핸들러와 함께 사용자 정의 로거를 사용하십시오. 이것은 처리되지 않은 예외를 변경하여 stderr이 아닌 stdout으로 이동하지만 동일한 스타일의 모든 종류의 핸들러를 로거 오브젝트에 추가 할 수 있습니다.


13
logger.critical()잡히지 않은 예외는 매우 중요하기 때문에 excepthook 핸들러 내부에서 사용 합니다.
gitaarik 2016 년

2
이것이 가장 실용적인 답변입니다.
David Morales

스 니펫 주셔서 감사합니다. 어떤 파일에 넣을까요?
stelios

@chefarov 다른 모든 로깅을 초기화하는 기본 파일
gnu_lorien

안녕하세요,이 정보를 debug.log와 같은 파일에 어떻게 쓸 수 있습니까? 나는 그것을 추가하려고 노력했지만 logging.basicConfig(level=logging.DEBUG, filename="debug.log", format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')도움이되지 않았다.
GurhanCagin

26

sys.excepthook예외가 발생하지 않으면 메소드 가 호출됩니다. http://docs.python.org/library/sys.html#sys.excepthook

예외가 발생하여 포착되지 않으면 인터프리터는 세 개의 인수, 예외 클래스, 예외 인스턴스 및 추적 백 오브젝트와 함께 sys.excepthook을 호출합니다. 대화식 세션에서는 제어가 프롬프트로 리턴되기 직전에 발생합니다. 파이썬 프로그램에서 이것은 프로그램이 종료되기 직전에 발생합니다. 이러한 최상위 예외 처리는 sys.excepthook에 다른 3 개의 인수 함수를 할당하여 사용자 지정할 수 있습니다.


2
왜 예외 클래스를 보내나요? type인스턴스 를 호출 하여 항상 얻을 수는 없습니까?
Neil G

매개 변수의 유형은 무엇입니까 sys.excepthook?
마틴 토마

23

왜 안되 겠어요 :

import sys
import logging
import traceback

def log_except_hook(*exc_info):
    text = "".join(traceback.format_exception(*exc_info))
    logging.error("Unhandled exception: %s", text)

sys.excepthook = log_except_hook

None()

sys.excepthook위 의 출력은 다음과 같습니다 .

$ python tb.py
ERROR:root:Unhandled exception: Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

다음은 sys.excepthook주석 처리 된 출력입니다 .

$ python tb.py
Traceback (most recent call last):
  File "tb.py", line 11, in <module>
    None()
TypeError: 'NoneType' object is not callable

유일한 차이점은 전자가 ERROR:root:Unhandled exception:첫 줄의 시작 부분에 있다는 것입니다.


또 다른 차이점은 전자가 추적을 로깅 시스템에 기록하므로 설치 한 모든 처리기 및 포맷터가 적용된다는 것입니다. 후자는에 직접 씁니다 sys.stderr.
radiaph

8

Jacinda의 답변을 기반으로하지만 로거 객체를 사용하려면 다음을 수행하십시오.

def catchException(logger, typ, value, traceback):
    logger.critical("My Error Information")
    logger.critical("Type: %s" % typ)
    logger.critical("Value: %s" % value)
    logger.critical("Traceback: %s" % traceback)

# Use a partially applied function
func = lambda typ, value, traceback: catchException(logger, typ, value, traceback)
sys.excepthook = func

2
functools.partial()람다 대신 사용 하는 것이 좋습니다 . 참조 : docs.python.org/2/library/functools.html#functools.partial
Mariusz Jamro

@MariuszJamro 왜?
davr

4

try...except잡히지 않은 예외를 모두 포착하고 기록 (및 다시 발생할 수 있음) 할 수 있도록 앱 항목 호출을 차단합니다. 예를 들어 :

if __name__ == '__main__':
    main()

이 작업을 수행:

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        logger.exception(e)
        raise

이것은 묻는 질문이 아닙니다. 문제는 코드로 예외를 처리하지 않을 때 수행 할 작업을 묻는 것입니다.
Mayank Jaiswal

1
글쎄, 파이썬은 프로그래밍 언어이며, 이것은 당신이 그것을 요구할 를 제외하고는 (자동으로) (OP가 원하는대로) 일 을하지 않는다는 것을 의미합니다. 다시 말해, 코드를 작성하지 않으면 모든 예외를 "자동으로"기록 할 수있는 방법이 없습니다. 이것이 바로 제 대답입니다.
flaviovs

1
Ned Batchelder의 답변을 보면 예외 후크라는 것이 있습니다. 코드에서 한 곳에 정의해야하며 포착되지 않은 모든 예외가 처리됩니다.
Mayank Jaiswal

1
예외 후크는 "자동"(OP가 원한다는 의미)이 아니라는 사실을 변경하지 않습니다. 즉, 여전히 코딩해야합니다. (예외 후크를 사용) 네드의 대답은 정말 원래의 질문을 해결 - 그냥 것을의 내 의견으로는 , 그것은 그 작업을 수행하는 방식이 훨씬 덜 파이썬 내보다.
flaviovs

1
그것은 당신의 목표에 달려 있습니다. IDE를 만족 시키도록 프로그램하면 모든 예외를 잡는 것이 옵션이 아닐 수 있습니다. 그러나 오류를 정상적으로 처리하고 사용자에게 좋은 피드백을 표시하려면 모든 예외를 잡아야 할 것 같습니다. 괜찮은 풍자 :-)-주의 깊게 살펴보면 코드가 예외를 가로채는 것을 알 수 있지만 다시 제기되므로 IDE가 "마법적인"일을하지 않으면 계속해서는 안됩니다. 예외.
flaviovs

3

어쩌면 모듈 상단에서 stderr를 파일로 리디렉션하고 하단에 해당 파일을 로깅하는 작업을 수행 할 수 있습니다

sock = open('error.log', 'w')               
sys.stderr = sock

doSomething() #makes errors and they will log to error.log

logging.exception(open('error.log', 'r').read() )

3

@gnu_lorien의 답변이 나에게 좋은 출발점이되었지만 내 프로그램은 첫 번째 예외에서 충돌합니다.

나는 꾸며진 기능의 예외를 자동으로 기록하는 맞춤형 (및 / 또는) 개선 된 솔루션을 제공했습니다 @handle_error.

import logging

__author__ = 'ahmed'
logging.basicConfig(filename='error.log', level=logging.DEBUG)


def handle_exception(exc_type, exc_value, exc_traceback):
    import sys
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    logging.critical(exc_value.message, exc_info=(exc_type, exc_value, exc_traceback))


def handle_error(func):
    import sys

    def __inner(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception, e:
            exc_type, exc_value, exc_tb = sys.exc_info()
            handle_exception(exc_type, exc_value, exc_tb)
        finally:
            print(e.message)
    return __inner


@handle_error
def main():
    raise RuntimeError("RuntimeError")


if __name__ == "__main__":
    for _ in xrange(1, 20):
        main()

2

수락 된 답변의 의견 섹션에서 논의 한 Mr.Zeus의 질문에 대답하기 위해 대화 형 콘솔 (PyCharm 2018-2019로 테스트 됨)에서 포착되지 않은 예외를 기록하는 데 사용합니다. 나는 sys.excepthook파이썬 쉘에서 작동하지 않는다는 것을 알았 으므로 더 깊이 보았고 sys.exc_info대신 사용할 수 있음을 발견했습니다 . 그러나 3 개의 인수를 취하는 sys.exc_info것과 달리 인수는 없습니다 sys.excepthook.

여기서는 대화식 콘솔과 래퍼 함수가있는 스크립트에서 모두 sys.excepthooksys.exc_info예외를 모두 기록합니다. 두 함수에 후크 함수를 연결하기 위해 인수가 제공되는지 여부에 따라 두 가지 다른 인터페이스가 있습니다.

코드는 다음과 같습니다.

def log_exception(exctype, value, traceback):
    logger.error("Uncaught exception occurred!",
                 exc_info=(exctype, value, traceback))


def attach_hook(hook_func, run_func):
    def inner(*args, **kwargs):
        if not (args or kwargs):
            # This condition is for sys.exc_info
            local_args = run_func()
            hook_func(*local_args)
        else:
            # This condition is for sys.excepthook
            hook_func(*args, **kwargs)
        return run_func(*args, **kwargs)
    return inner


sys.exc_info = attach_hook(log_exception, sys.exc_info)
sys.excepthook = attach_hook(log_exception, sys.excepthook)

로깅 설정은 gnu_lorien의 답변에서 찾을 수 있습니다.


2

python 3@Jacinda의 답변을 사용할 때 내 경우 (을 사용하여 ) 역 추적의 내용이 인쇄되지 않았습니다. 대신 객체 자체를 인쇄합니다 <traceback object at 0x7f90299b7b90>.

대신에 나는 :

import sys
import logging
import traceback

def custom_excepthook(exc_type, exc_value, exc_traceback):
    # Do not print exception when user cancels the program
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return

    logging.error("An uncaught exception occurred:")
    logging.error("Type: %s", exc_type)
    logging.error("Value: %s", exc_value)

    if exc_traceback:
        format_exception = traceback.format_tb(exc_traceback)
        for line in format_exception:
            logging.error(repr(line))

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