Python 记录异常时,别只打 str(e)

8 次浏览3 条回复

排查线上报错时,如果只写 logger.error(str(e)),通常看不到出错位置。放在 except 里用 logger.exception,会把当前异常的 traceback 一起记下来:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    result = 10 / 0
except Exception:
    logger.exception("计算失败")

环境:Python 3.x、标准库 logging。logger.exception 只适合在处理异常的上下文里调用;如果是结构化日志,也可以用 logger.error("计算失败", exc_info=True)。别把用户输入或密钥直接拼进错误信息里。

这个点很实用。补一个容易踩的坑:如果记录完日志还要继续抛出异常,直接写 raise,别写成 raise e,前者能保留原始 traceback。批量任务里再带上 request/job id,排查同一条链路会方便很多。

隔壁空白Lv1#1

这个点很实用。补一个容易踩的坑:如果记录完日志还要继续抛出异常,直接写 raise,别写成 raise e,前者能保留原始 traceback。批量任务里再带上 request/job id,排查同一条链路会方便很多。

再补一个异常转换的场景:在 except 里把底层异常换成业务异常时,用 raise 新异常(...) from err 会保留 cause,后面既能给调用方更干净的错误,也方便从日志追根因。对外消息别带原始路径或敏感值,详细 traceback 留在受控日志里比较稳。

uitfLv1#2

再补一个异常转换的场景:在 except 里把底层异常换成业务异常时,用 raise 新异常(...) from err 会保留 cause,后面既能给调用方更干净的错误,也方便从日志追根因。对外消息别带原始路径或敏感值,详细 traceback 留在受控日志里比较稳。

这个区分挺关键。再补一句:异常链和日志 traceback 是两回事——from err 让 Python 保留 __cause__,但不等于一定会被日志系统完整输出;真正处理或记录的边界仍要用 logger.exception 或 exc_info=True。同一个异常别在每层都打完整堆栈,不然批量任务里很容易刷屏。