IT박스

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

itboxs 2020. 6. 7. 10:48
반응형

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


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

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

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

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


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: http://docs.python.org/library/sys.html#sys.excepthook


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

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으로 이동하지만, 동일한 스타일의 모든 핸들러를 로거 오브젝트에 추가 할 수 있습니다.


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

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


왜 안되 겠어요 :

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:첫 줄의 시작 부분에 있다는 것입니다.


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

Wrap your app entry call in a try...except block so you'll be able to catch and log (and perhaps re-raise) all uncaught exceptions. E.g. instead of:

if __name__ == '__main__':
    main()

Do this:

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

Maybe you could do something at the top of a module that redirects stderr to a file, and then logg that file at the bottom

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

Although @gnu_lorien's answer gave me good starting point, my program crashes on first exception.

I came with a customised (and/or) improved solution, which silently logs Exceptions of functions that are decorated with @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()

To answer the question from Mr.Zeus discussed in the comment section of the accepted answer, I use this to log uncaught exceptions in an interactive console (tested with PyCharm 2018-2019). I found out sys.excepthook does not work in a python shell so I looked deeper and found that I could use sys.exc_info instead. However, sys.exc_info takes no arguments unlike sys.excepthook that takes 3 arguments.

Here, I use both sys.excepthook and sys.exc_info to log both exceptions in an interactive console and a script with a wrapper function. To attach a hook function to both functions, I have two different interfaces depending if arguments are given or not.

Here's the code:

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)

The logging setup can be found in gnu_lorien's answer.

참고URL : https://stackoverflow.com/questions/6234405/logging-uncaught-exceptions-in-python

반응형