跳到内容

第 0 卷 / 第 6 章 / 第 3 课

6.3 安全检索与最小复现 ​

前置知识:读懂错误、日志基础

预计时间:15 分钟

完成标志:能构造脱敏查询,并交付别人可从干净目录运行的最小复现

日志保留了故障证据,却不等于根因已经清楚。查资料之前,先把原始记录留在受控位置:搜索框、公开 Issue 和聊天窗口都不是生产日志的默认去处。

搜不到的错 ​

以这条数据库错误为例:

text
org.postgresql.util.PSQLException:
ERROR: duplicate key value violates unique constraint "users_pkey"

如果盯着 duplicate 猜了半小时仍没有进展,可以搜索;但不要把生产日志当成公开文本。

第一步:在本地制作可分享副本 ​

原始错误先留在受控位置。复制一份,再删除或替换:

  • 密码、令牌、API 密钥、Cookie 和会话标识;
  • 数据库连接串、私有仓库地址和内部主机名;
  • 客户数据、个人信息、邮件、手机号和真实业务编号;
  • 本地用户名、绝对路径、内网 IP;
  • 与问题无关的请求正文、时间戳、随机 ID 和栈帧。

使用 <ACCESS_TOKEN>、<USER_ID> 这类占位符,而不是把值模糊到看不出字段含义。仅保留前后几位仍可能泄密。

第二步:构造能命中同类问题的查询 ​

从下面这类稳定片段开始:

text
PSQLException duplicate key value violates unique constraint PostgreSQL 17 JDBC

操作顺序:

  1. 保留异常类型和通用消息;
  2. 删除每次变化的 ID、路径、时间和行号;
  3. 只添加相关的语言、框架与确切版本;
  4. 先核对当前版本官方文档和项目 Issue,再参考社区回答;
  5. 在隔离环境用最小复现验证,别直接执行陌生的删除、权限或安装命令。

这条数据库消息证明唯一约束冲突,却没有证明是重复提交、序列不同步、主键生成错误还是残留测试数据。搜索结果只提供假设。

第三步:把五百行缩成可运行证据 ​

把 Spring Boot、PostgreSQL、连接池、路由和缓存一起打包发出去,对方得先搭完整项目才有机会看见错误。先删掉与失败条件无关的部分,能省下大量准备工作。

一个合格的最小复现应包含:

内容要写到什么程度
环境操作系统、运行时、框架和相关依赖的确切版本
文件只保留触发问题所需内容,附目录结构
准备步骤从干净目录开始的完整命令
输入最小、虚构或已脱敏的数据
复现步骤每一步可复制,说明工作目录
预期结果具体到输出、状态或返回值
实际结果完整但已脱敏的错误和退出码
范围信息最后正常版本、首次异常版本、已排除项

怎样缩减而不把 bug 一起删掉 ​

  1. 先在副本中稳定复现原现象。
  2. 固定一条运行命令和一份输入。
  3. 每次只删除一个模块、配置或依赖。
  4. 每次都运行同一测试,记录仍能否复现。
  5. 用假实现替代数据库或 API;若真实边界正是条件,就保留它并提供安全的本地替代环境。
  6. 如果再删一步就不再复现,撤销最后这次缩减;交付的仍应是能复现的版本。

最小不等于“只有一行”,完整也不等于“整个仓库”。目标是保留导致现象的所有条件,删除其余变量。

一个可交付的 README 模板 ​

markdown
# Reproduction: concise problem name

## Environment
- OS:
- Runtime:
- Framework / dependency versions:

## Run
1. From this directory, run: `...`
2. Observe the process exit code: `...`

## Expected
...

## Actual
...

## Notes
- Last known good version:
- First known bad version:
- Variables already ruled out:

不要只发截图。文本便于检索、复制和辅助技术读取;截图可以补充界面状态,但不能替代命令、文本错误和文件。

提问前的安全检查 ​

  • [ ] 示例不含真实密钥、Cookie 或连接串;
  • [ ] 用户与客户数据已换成虚构数据;
  • [ ] 私有 URL、主机名和路径已替换;
  • [ ] 问题在新目录或新容器中仍能重现;
  • [ ] 锁文件或依赖版本信息已附上;
  • [ ] 预期与实际结果分开写明;
  • [ ] 你没有预设“肯定是某库的 bug”,只陈述观察结果。

离开这一页前 ​

  • 把示例数据库错误改写成不含项目标识的搜索查询;
  • 从一个现有问题副本中逐项删除变量,保留每次运行记录;
  • 让另一个人只看 README 就能复现;
  • 能解释“搜索结果是候选原因,不是诊断结论”。

理论已经齐了。现在亲手捕获退出码、核对栈帧、检查日志,并处理一个常被讲错的 Java 依赖案例。

→ 下一步:综合排障实验

Built with VitePress | Software Systems Atlas