如何通过日志模块而不是stderr导致未捕获的异常输出?

我意识到最好的办法是:

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

但我的情况是,如果在没有捕获异常时自动调用logging.exception(…),那就太好了。


当前回答

下面是一个完整的小例子,还包括一些其他技巧:

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

忽略KeyboardInterrupt,这样控制台python程序就可以用Ctrl + C退出。 完全依赖python的日志模块来格式化异常。 使用带有示例处理程序的自定义日志记录器。这一个将未处理的异常更改为stdout而不是stderr,但是您可以以相同的样式向记录器对象添加各种处理程序。

其他回答

正如奈德指出的,系统。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. exe的详细信息。但是,看看这些文件。

下面是一个完整的小例子,还包括一些其他技巧:

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

忽略KeyboardInterrupt,这样控制台python程序就可以用Ctrl + C退出。 完全依赖python的日志模块来格式化异常。 使用带有示例处理程序的自定义日志记录器。这一个将未处理的异常更改为stdout而不是stderr,但是您可以以相同的样式向记录器对象添加各种处理程序。

虽然@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()

也许你可以在模块的顶部做一些事情,将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() )

在我的情况下(使用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