在 Python 中记录未捕获的异常

2025-01-21 09:01:00
admin
原创
87
摘要:问题描述:如何使未捕获的异常通过logging模块而不是输出stderr?我意识到做到这一点的最佳方式是:try: raise Exception, 'Throwing a boring exception' except Exception, e: logging.exception(e) ...

问题描述:

如何使未捕获的异常通过logging模块而不是输出stderr

我意识到做到这一点的最佳方式是:

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

但我的情况是这样的,如果在未捕获到异常时自动调用它,那就太好了。logging.exception(...)


解决方案 1:

这是一个完整的小例子,其中还包含一些其他技巧:

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,但您可以向记录器对象添加相同样式的各种处理程序。

解决方案 2:

正如 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,请阅读文档。

解决方案 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:在第一行的开头有。

解决方案 4:

sys.excepthook如果未捕获异常,则将调用该方法: http://docs.python.org/library/sys.html#sys.excepthook

当引发异常但未被捕获时,解释器会使用三个参数调用 sys.excepthook,即异常类、异常实例和回溯对象。在交互式会话中,这会在控制权返回提示符之前发生;在 Python 程序中,这会在程序退出之前发生。可以通过将另一个三参数函数分配给 sys.excepthook 来自定义此类顶级异常的处理。

解决方案 5:

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

解决方案 6:

以 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

解决方案 7:

尽管@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()

解决方案 8:

将应用程序入口调用包装在一个try...except块中,这样您就可以捕获并记录(并可能重新引发)所有未捕获的异常。例如,而不是:

if __name__ == '__main__':
    main()

这样做:

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

解决方案 9:

为了回答 Mr.Zeus 在已接受答案的评论部分中讨论的问题,我使用它在交互式控制台中记录未捕获的异常(使用 PyCharm 2018-2019 测试)。我发现sys.excepthook在 python shell 中不起作用,所以我深入研究并发现我可以使用它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 的回答中找到日志设置。

解决方案 10:

也许你可以在模块顶部做一些事情,将 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() )
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用