# Root Cause Tracing

> Root Cause Tracing

- Skill: `hongmaple0820/root-cause-tracing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add hongmaple0820/root-cause-tracing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hongmaple0820/root-cause-tracing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: hongmaple0820 (https://skillmd.com/u/hongmaple0820)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/hongmaple0820/root-cause-tracing

---

# Root Cause Tracing

追踪错误的根本原因，找到问题的真正源头。

## 激活场景

- 遇到复杂的错误或 bug
- 错误信息不够清晰
- 需要从错误点回溯到源头
- 用户说"找原因"、"为什么出错"、"根因分析"

## 核心思想

错误的表现往往不是真正的原因。需要逐层回溯，找到触发问题的根源。

```
症状 → 直接原因 → 间接原因 → 根本原因
```

## 分析流程

### 1. 收集信息

```bash
# 查看完整错误堆栈
cat error.log | tail -100

# 查看相关日志
grep -B 10 -A 5 "ERROR" app.log

# 查看系统状态
dmesg | tail -50
```

记录以下信息：
- 错误消息
- 完整堆栈跟踪
- 发生时间
- 触发条件
- 环境信息

### 2. 5 Whys 分析法

连续问 5 次"为什么"，直到找到根本原因。

**示例**：

**问题**：用户无法登录

1. **为什么？** → 服务器返回 500 错误
2. **为什么？** → 数据库查询失败
3. **为什么？** → 数据库连接超时
4. **为什么？** → 连接池耗尽
5. **为什么？** → 有代码没有正确释放连接 ← **根本原因**

### 3. 堆栈追踪

从错误点开始，逐层向上追踪：

```
Error: Connection timeout
    at Database.query (db.js:45)        ← 直接错误点
    at UserService.findById (user.js:23) ← 调用者
    at AuthController.login (auth.js:67) ← 更上层
    at Router.handle (router.js:89)      ← 路由层
```

检查每一层：
- 输入是什么？
- 预期行为是什么？
- 实际发生了什么？

### 4. 时间线分析

```
10:00:00 - 系统正常
10:05:00 - 部署了新版本
10:10:00 - 开始出现错误
10:15:00 - 错误数量激增
```

关键问题：
- 什么变化发生在错误之前？
- 是逐渐恶化还是突然发生？
- 是否有周期性？

### 5. 隔离测试

```bash
# 测试单个组件
curl http://localhost:3000/health

# 测试数据库连接
mysql -h localhost -u root -p -e "SELECT 1"

# 测试网络
ping api.example.com
curl -I https://api.example.com
```

逐个排除可能的原因。

## 常见根因类别

### 代码问题

| 类型 | 特征 | 解决方向 |
|------|------|----------|
| 空指针 | `Cannot read property of undefined` | 添加空值检查 |
| 类型错误 | `TypeError` | 验证输入类型 |
| 竞态条件 | 偶发性失败 | 添加锁/同步机制 |
| 内存泄漏 | 随时间恶化 | 检查资源释放 |
| 死锁 | 卡住不动 | 检查锁的顺序 |

### 配置问题

| 类型 | 特征 | 解决方向 |
|------|------|----------|
| 环境变量缺失 | 启动时失败 | 检查 .env 文件 |
| 权限不足 | Permission denied | 检查文件/目录权限 |
| 端口冲突 | Address in use | 检查端口占用 |
| 路径错误 | File not found | 检查相对/绝对路径 |

### 外部依赖

| 类型 | 特征 | 解决方向 |
|------|------|----------|
| API 变更 | 字段缺失 | 检查 API 文档 |
| 服务不可用 | Connection refused | 检查服务状态 |
| 超时 | Timeout | 增加超时时间或重试 |
| 限流 | 429 Too Many Requests | 添加限流/重试逻辑 |

## 调试工具

### 日志分析

```bash
# 按时间过滤
grep "2024-02-06 10:" app.log

# 统计错误类型
grep "ERROR" app.log | cut -d':' -f4 | sort | uniq -c | sort -rn

# 追踪请求
grep "request-id-123" app.log
```

### 性能分析

```bash
# 查看进程状态
top -p $(pgrep node)

# 查看打开的文件
lsof -p $(pgrep node) | wc -l

# 查看网络连接
netstat -an | grep ESTABLISHED | wc -l
```

### 数据库分析

```sql
-- 查看慢查询
SHOW PROCESSLIST;

-- 查看锁
SHOW ENGINE INNODB STATUS;

-- 查看连接数
SHOW STATUS LIKE 'Threads_connected';
```

## 输出格式

### 根因分析报告

```markdown
# 根因分析报告

## 问题描述
用户登录时返回 500 错误

## 时间线
- 10:05 - 部署版本 v1.2.3
- 10:10 - 首次出现错误
- 10:20 - 错误率达到 30%
- 10:30 - 回滚到 v1.2.2
- 10:35 - 错误消失

## 根本原因
新版本中修改了数据库查询，缺少对空结果的处理，
导致后续代码尝试访问 undefined 的属性。

## 直接原因
`user.profile.name` 访问失败，因为 `user.profile` 为 null

## 触发条件
- 新注册用户尚未设置 profile
- 占用户总数约 5%

## 解决方案
1. 添加空值检查：`user.profile?.name`
2. 添加单元测试覆盖此场景
3. 添加数据迁移脚本初始化空 profile

## 预防措施
- 代码审查时检查空值处理
- 添加更多边界条件测试
- 灰度发布降低影响范围
```

## 思维模式

1. **假设-验证**：提出假设，设计实验验证
2. **二分法**：缩小问题范围，定位问题区域
3. **对比法**：对比正常和异常情况的差异
4. **最小复现**：找到能复现问题的最小条件
5. **反向推理**：从结果倒推可能的原因

