Python 中如何记录未捕获的异常?

Python 记录未捕获异常:设置 sys.excepthook 自定义全局异常处理器,将异常信息写入日志。threading.excepthook 处理子线程异常。本文给出完整实现。

最佳实践
Python 中如何记录未捕获的异常?封面

核心:覆盖 sys.excepthook 钩子函数,在其中调用 logger 记录异常详情。这样即使代码没有 try-except,崩溃前也会留下完整的错误日志。

完整实现

import sys
import logging

logging.basicConfig(filename='error.log', level=logging.DEBUG)
logger = logging.getLogger(__name__)

def handle_unhandled_exception(exc_type, exc_value, exc_traceback):
    if issubclass(exc_type, KeyboardInterrupt):
        # Ctrl+C 不记录,走默认行为
        sys.__excepthook__(exc_type, exc_value, exc_traceback)
        return
    logger.critical("未捕获的异常", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_unhandled_exception

# 测试:这行代码的异常会被记录到 error.log
raise ValueError("这是一个测试异常")

子线程的异常

sys.excepthook 只捕获主线程的未处理异常。Python 3.8+ 对子线程有独立的钩子:

import threading

def handle_thread_exception(args):
    logger.error(f"线程 {args.thread.name} 异常", exc_info=(args.exc_type, args.exc_value, args.exc_traceback))

threading.excepthook = handle_thread_exception

装饰器方式(函数级)

对特定函数记录异常:

import functools

def log_exceptions(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception:
            logger.exception(f"{func.__name__} 执行出错")
            raise
    return wrapper

@log_exceptions
def process_data():
    ...

观测云对照

生产环境推荐用观测云 APM 的 Python 探针,自动捕获未处理异常并关联到请求 Trace,包含堆栈和上下文,不需要手动设置钩子。

常见问题(FAQ)

Q:excepthook 里记录完程序会退出吗?
A:会。excepthook 在异常导致程序终止前被调用,你只能在其中记录日志,无法阻止退出。

Q:logging.exception() 和 logging.error(exc_info=True) 有什么区别?
A:logging.exception() 自动附带当前异常的堆栈(必须在 except 块中调用),等价于 logging.error(..., exc_info=True)

Q:异步代码(asyncio)的异常呢?
A:asyncio 有自己的异常处理:loop.set_exception_handler() 或在协程中加 try-except。未处理的 Task 异常在事件循环关闭时才报告。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台