# 自动报表出错后怎么保留排查证据：用 logging 记录阶段、参数和异常堆栈

## 文档明确的机制

无人值守的数据处理脚本最怕“半夜失败，早上只看到没生成报表”。Python 标准库 `logging` 的定位，是为应用和库提供灵活的事件日志系统；各模块都可以参与日志，因此应用自身消息能与第三方模块消息整合。排查报表任务时，这有助于把读取、清洗、计算、发送等位置串成一条时间线。

官方示例推荐在模块内使用：

`logger = logging.getLogger(__name__)`

同名的多次 `getLogger()` 调用会返回同一个 `Logger` 对象。使用 `__name__` 时，logger 名称与 Python 包和模块的命名层级对应。底层模块记录的消息会向更高层模块的 handler 转发，直到 root logger，这就是层级日志。多数情况下，只配置 root logger 即可；`basicConfig()` 是文档给出的快速配置 root logger 的方式，可用于设置文件名和级别。官方示例使用 `logging.basicConfig(filename='myapp.log', level=logging.INFO)`，日志结果包含级别、模块名和消息。

日志系统的职责也有明确分工：`Logger` 是应用代码直接使用的接口；`Handler` 把 logger 创建的日志记录发送到合适目的地；`Formatter` 规定日志记录最终输出的布局；`Filter` 则可更细粒度地决定哪些记录被输出。因此，“写到哪里”和“长什么样”不应混在业务日志调用里。

级别方面，文档列出：DEBUG 为 10，用于开发者诊断问题的详细信息；INFO 为 20，表示事情按预期运行的确认；WARNING 为 30，表示发生意外情况或近期可能出现问题，但软件仍按预期工作；ERROR 为 40，表示由于更严重的问题，软件无法执行某项功能；CRITICAL 为 50，表示严重错误，程序本身可能无法继续运行。报表脚本可用 INFO 标记阶段进展，用 WARNING 记录可继续但需留意的问题，用 ERROR 记录某一步失败。

异常信息有边界清楚的写法。`Logger.exception()` 会以 ERROR 级别记录消息，并把异常信息加入日志，但文档明确说明它只应在异常处理器中调用。普通 `debug()`、`info()`、`warning()`、`error()` 等方法支持 `exc_info` 参数；当 `exc_info` 为真值时，异常信息会被加入日志消息。它可以接受异常元组或异常实例，否则调用 `sys.exc_info()` 获取异常信息。

层级传播还需注意重复输出。`propagate` 为真时，事件会传给祖先 logger 的 handler；如果在一个 logger 及其一个或多个祖先上都挂 handler，同一记录可能输出多次。文档建议通常只需把 handler 挂在层级中合适的最高层 logger，常见场景是只挂到 root logger，并让传播处理其余日志。

## 团队自行约定的接手建议

以下是实施建议，并非 `logging` 文档宣称的额外产品能力。

第一，给每个阶段固定一条 INFO 日志，例如“读取开始”“清洗完成”“计算完成”“发送开始”。消息中记录可核验上下文字段，如输入文件名、处理行数、关键输入参数。这样接手者可以根据最后一条成功阶段判断失败大致位置。

第二，在 `except` 块中优先使用 `logger.exception("发送报表失败")`，让 ERROR 日志包含 traceback；若在不适合 `exception()` 的通用日志位置需要异常信息，再显式使用 `exc_info`。不要只写“出错了”，否则仍缺少异常类型和调用栈。

第三，团队可统一 Formatter，让输出至少包含时间、级别、模块名和消息；这样从多个模块传播到 root logger 的记录仍能按时间阅读。是否额外加入函数名、行号或自定义字段，应按团队排障需要确定。

第四，日志应脱敏，禁止记录密码、密钥、原始令牌等敏感信息。客户标识、报表参数等也应按团队规则最小化记录。这里的脱敏、字段审批和保存期限都需要团队自行落实，不能理解为标准库自动完成。

第五，不要把 WARNING 当 ERROR：任务仍完成但存在缺行、空文件等需留意情况时可记录 WARNING；某功能已经无法执行时使用 ERROR。这样接手者能区分“需要复核”和“流程中断”。

## 边界与总结

`logging` 负责产生、分发和格式化日志记录。它不会因为写入 ERROR 日志就自动重试读取、重新计算报表、修复脏数据或恢复发送任务；是否重试、怎样补偿，需要任务代码另行设计，不能把日志能力扩大解释。

排查证据的关键不是多打日志，而是让每条记录回答三个问题：任务走到哪个阶段、当时使用什么输入、失败异常是什么。结合 `getLogger(__name__)` 的模块层级、root logger 的统一 handler、Formatter 的固定布局，以及 `exception()` 或 `exc_info` 对 traceback 的记录，无人值守报表失败后就能留下更可接手的证据。

## 相关工具

[AI 工作流 ROI 诊断器](/demos/ai-workflow-roi-diagnostic/index.html) · 查看工具的输入要求、输出说明与适用范围。


来源：[自动报表出错后怎么保留排查证据：用 logging 记录阶段、参数和异常堆栈](https://docs.python.org/3/library/logging.html)
