Skip to content

fix(logging): 按 loguru 契约传递占位符和异常信息 - #1139

Merged
xerrors merged 1 commit into
xerrors:mainfrom
Ashitaka-Laputa-IV:fix/loguru-logging-contract
Nov 2, 2026
Merged

xerrors merged 1 commit into
xerrors:mainfrom
Ashitaka-Laputa-IV:fix/loguru-logging-contract

Conversation

@Ashitaka-Laputa-IV

@Ashitaka-Laputa-IV Ashitaka-Laputa-IV commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

问题

项目统一使用 loguru,但部分调用仍按标准 logging 的习惯传递 %s 占位符和 exc_info=True。loguru 使用 {} 格式化,%s 会原样留在日志中;exc_info 不是 loguru 的异常参数,logger.error(..., exc_info=True) 不会输出堆栈。受影响日志覆盖 Run 派发、lease 续租、后台作业、取消恢复和 Langfuse 清理,排障时丢失 run_id、job_id、turn_id、phase 与 traceback。

复现:

from loguru import logger
logger.warning("value=%s", 42)  # 输出 value=%s

改动

  • 将 loguru 调用中的 %s/%d/%i/%f/%r 占位符改为 {}。
  • 将 logger.error/warning(..., exc_info=True) 改为 logger.opt(exception=True).error/warning(...)。
  • 保留 sandbox_runner 与 tool_error_guard 中标准 logging 的 %s 用法。
  • 新增静态 unit guard:解析源码 AST,拒绝 loguru 调用中的 % 占位符与 exc_info 关键字;同时提供负向样例和标准 logging 不误报样例。
  • 新增决定记录:docs/develop-guides/decisions/implemented/2026-11-02-loguru-logging-contract.md。

验证

已执行:

cd backend
uv run --python 3.12 --group test pytest test/unit/server/test_loguru_logging_contract.py --noconftest -q
# 5 passed

uv run ruff check yuxi test/unit/server/test_loguru_logging_contract.py
# All checks passed

uv run ruff format yuxi test/unit/server/test_loguru_logging_contract.py --check
# 447 files already formatted

uv run ruff check --select I yuxi test/unit/server/test_loguru_logging_contract.py
# All checks passed

python scripts/ci/verify_engineering_contracts.py
# 工程信任检查通过

风险

仅日志文本与异常堆栈变化,不改变业务状态、接口、持久化或事件顺序。新增 guard 会阻止后续 loguru 调用重新引入标准 logging 约定。

loguru 使用 {} 格式化,标准 logging 的 %s 占位符会原样输出,exc_info
关键字也不会附加堆栈。统一改为 {} 与 logger.opt(exception=True),并新增
静态 unit guard 防止回归。

验证:新增 guard 5 passed;ruff check/format/import 检查通过;
verify_engineering_contracts 通过。完整 unit/integration 未在当前 Windows
环境运行。

@xerrors xerrors left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

独立语义审查通过。审查基于完整 PR 差异及与当前 main c792eabca 的无冲突合并候选,PR head 为 9e80d5e2d97227d539b27b84eaabc0f557003cc3。17 个生产模块的修改均限于 loguru 调用,没有误改标准 logging 或业务控制流;独立 Reviewer 对旧源码的负控发现 55 处违规,真实 loguru sink 也确认插值和 traceback 得到修复。没有未解决的可行动问题。

维护者验证:

  • 合并候选完整后端 unit:3644 passed、11 skipped,JUnit 已回读;跳过项不计为通过。
  • 新日志契约测试:5 passed。
  • 工程 verifier 通过;验证器单测 56 项通过。
  • Ruff lint、format、import 检查全部通过;文档构建和补丁检查通过。
  • CodeQL 已通过;合并前继续等待现有 CI 的服务集成和系统 E2E,不用本地 unit 结果替代它们。

实际命令(在独立检出执行,未更改主工作区、未重启业务服务):

python3 scripts/ci/verify_engineering_contracts.py
python3 -m unittest scripts.ci.test_verify_engineering_contracts
git diff --cached --check
/home/zwj/workspace/projects/Yuxi-v1/backend/.venv/bin/ruff check backend/yuxi backend/test/unit/server/test_loguru_logging_contract.py
/home/zwj/workspace/projects/Yuxi-v1/backend/.venv/bin/ruff format backend/yuxi backend/test/unit/server/test_loguru_logging_contract.py --check
/home/zwj/workspace/projects/Yuxi-v1/backend/.venv/bin/ruff check --select I backend/yuxi backend/test/unit/server/test_loguru_logging_contract.py
node docs/node_modules/vitepress/bin/vitepress.js build docs

完整 unit 使用现有 Compose API 镜像,但放在无网络、没有业务数据挂载的一次性容器中,确保读取的是 PR 与当前 main 的合并候选:

docker run --rm --network none --group-add 1001 --entrypoint /bin/sh --mount type=bind,source=/tmp/yuxi-pr1139-merge-20261102,target=/repo --mount type=bind,source=/tmp/yuxi-pr1139-evidence,target=/evidence --workdir /repo/backend -e PYTHONPATH=/repo/backend -e PYTHONDONTWRITEBYTECODE=1 main-api:0.8.0.beta6 -c 'uv run --no-sync --group test pytest test/unit -m "not slow" -q -o cache_dir=/tmp/pytest-cache --junitxml=/evidence/unit.xml'

首次执行因容器与宿主 UID 不一致,JUnit 报告写入失败,未计为通过;修正临时报告目录组权限后,上述完整集合重新执行并成功落盘。未在本地运行真实外部模型、完整服务集成或 E2E;后两者以当前 CI 结果为准。纯日志调用修复不改变业务状态、权限或持久化。

@xerrors

xerrors commented Nov 2, 2026

Copy link
Copy Markdown
Owner

合并前补充验证:当前 CI 与 CodeQL 均已成功,CI required 通过。已下载并逐份解析 JUnit,全部报告 0 failures、0 errors;系统验证合计 450 个 testcase,0 skipped。前端与依赖工作流按现有 selector 未选择,没有将它们计为通过。

本地 API 镜像 unit 的 11 项 skip 均因镜像缺 Docker Compose CLI;已对同一合并候选在宿主执行以下命令,207 passed、0 skipped,覆盖这些部署配置检查:

PYTHONPATH=/tmp/yuxi-pr1139-merge-20261102/backend /home/zwj/workspace/projects/Yuxi-v1/backend/.venv/bin/python -m pytest backend/test/unit/config -q -o cache_dir=/tmp/yuxi-pr1139-config-cache --junitxml=/tmp/yuxi-pr1139-evidence/config.xml

远端其余 skip 如实保留:

  • backend-unit-junit/unit.xml / test_preinstalled_model_dir_covers_requested_models:未配置预置模型目录
  • service-integration-junit/service-integration.xml / test_mcp_document_pages_use_current_permission_and_bounded_wire_payload:需要独立的临时对象存储

合并候选 tree 为 89fe48790a2bd2fe76853fbe2de4383136415844;已复核 base/head 未变化,准备按正常 merge 流程合并,不使用管理员绕过。

@xerrors
xerrors merged commit 7b75216 into xerrors:main Nov 2, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants