必须传 exc_info=true 或用 logging.exception() 才能保留 traceback,因 str(e) 仅转异常为字符串而丢失堆栈;exc_info=true 需在异常上下文活跃时调用,且日志格式须含 %(exc_text)s 才能显示堆栈。

直接用 logging.error() 打印异常字符串,堆栈就没了——这是最常踩的坑。想保留完整 traceback,必须显式传 exc_info=True 或改用 logging.exception()。
为什么 logging.error(str(e)) 不会输出堆栈
因为 str(e) 只是把异常转成一行字符串,比如 "division by zero",原始的调用链、文件名、行号全被丢弃。日志里只有一句话,根本没法定位问题在哪一层出的错。
-
logging.error("出错了: " + str(e))→ 永远只有错误文本,无 traceback -
logging.error("出错了", exc_info=True)→ 自动附加当前sys.exc_info()的完整堆栈 - 即使你手动拼了
repr(e)或e.args,也还是没堆栈
exc_info=True 必须在异常上下文活跃时调用
Python 的异常上下文(即 sys.exc_info() 返回的元组)只在 except 块内或刚退出时有效。一旦执行过其他语句(比如 print()、函数调用、变量赋值),上下文就可能被覆盖或清空。
- ✅ 正确:
except ValueError as e: logging.error("解析失败", exc_info=True) - ❌ 危险:
except ValueError as e: do_something(); logging.error("解析失败", exc_info=True)→ 可能记录空堆栈或前一个异常 - 若需延迟记录,先保存:
exc_info = sys.exc_info(),再传exc_info=exc_info
自定义日志格式必须含 %(exc_text)s
哪怕你传了 exc_info=True 或用了 logging.exception(),如果日志格式里没写 %(exc_text)s,堆栈照样不会显示——它会被静默丢弃。
- 默认格式(如
basicConfig(format="%(message)s"))不含该字段 → 堆栈消失 - 推荐格式:
format="%(asctime)s %(levelname)s %(message)s%(exc_text)s" -
%(exc_text)s是唯一能渲染 traceback 字符串的占位符,不能用%(exception)s或其他变体代替
真正容易被忽略的是:exc_info=True 不是“开关”,而是一次性快照;它依赖 Python 解释器当前的异常状态,而这个状态比多数人想象中更脆弱。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











