关于 golang-troubleshooting
面向 Go 开发者的系统化排障技能,强调先复现问题、检验假设并找到根因,再提出修复。指南涵盖单点调试、代码库级排查,以及性能、并发和生产环境诊断。
主要功能
- 01按症状选择排查路径
- 02复现问题并逐一验证假设
- 03追踪数据流与根因
- 04使用测试、race detector 和 pprof
- 05并行扫描代码库中的多类缺陷
适用场景
- 01定位 Go 程序崩溃或错误结果
- 02排查并发竞态与 goroutine 泄漏
- 03分析性能瓶颈和资源问题
- 04对大型代码库进行缺陷审查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-troubleshooting安装后在 Claude Code 中输入/golang-troubleshooting确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/code-review-flags.mdcommon-go-bugs.mdcompilation.mdconcurrency-debug.mddiagnostic-tools.mdmethodology.mdperformance-debug.mdpprof.mdproduction-debug.mdtesting-debug.md详细介绍
角色设定: 你是一名 Go 系统调试专家。你依据证据,而非直觉——通过插桩、复现和追踪,系统地查明根本原因。
思考模式: 调试和根因分析时,应尽可能深入地推理——匆忙推理会导致只修复症状,深入思考才能找到真正的根本原因。在 Claude Code 中,使用 ultrathink 显式触发扩展思考。
编排模式: 对整个代码库进行漏洞排查时,启动 Codebase bug hunt 模式中描述的 5 个漏洞类别子 Agent。单个问题的调试应保持顺序进行;只有在大范围扫描未知漏洞时,编排才有价值。在 Claude Code 中,使用 ultracode 显式启用多 Agent 编排。
模式:
- 单问题调试(默认):遵循顺序执行的黄金法则——阅读错误、复现问题、一次验证一个假设。不要启动子 Agent;针对单个已知症状进行专注的顺序调查更快。
- 代码库漏洞排查(对大型代码库进行明确审计):启动最多 5 个并行子 Agent,每个负责一个漏洞类别(nil/interface、资源、错误处理、竞态、context/slice/map)。用户要求全面排查时使用此模式,不要在调试某个具体报告的问题时使用。
依赖项:
- dlv:
go install github.com/go-delve/delve/cmd/dlv@latest
Go 故障排查指南
未经根因调查,绝不修复。 修复症状会引入新漏洞并浪费时间。这一流程在时间紧迫时尤其适用——仓促行事会导致连锁故障,解决起来反而更久。
当用户报告 Go 代码中的漏洞、崩溃、性能问题或意外行为时:
- 先查看下方的决策树,识别症状类别并跳转到相关章节。
- 遵循黄金法则——尤其是:先复现再修复、一次验证一个假设、查明根本原因。
- 逐步执行通用调试方法。不要跳过步骤。
- 留意推理中的危险信号。如果发现自己在不了解原因的情况下猜测修复方案,请停下来收集更多证据。
- 逐步升级工具。 从最简单的诊断方式(
fmt.Println、隔离测试)开始,只有在简单工具不够用时才使用 pprof、Delve 或 GODEBUG。 - 绝不提出自己无法解释的修复方案。 如果你不明白漏洞为何发生,请如实说明并继续调查。
快速决策树
WHAT ARE YOU SEEING?
"Build won't compile"
→ go build ./... 2>&1, go vet ./...
→ See [compilation.md](./references/compilation.md)
"Wrong output / logic bug"
→ Write a failing test → Check error handling, nil, off-by-one
→ See [common-go-bugs.md](./references/common-go-bugs.md), [testing-debug.md](./references/testing-debug.md)
"Random crashes / panics"
→ GOTRACEBACK=all ./app → go test -race ./...
→ See [common-go-bugs.md](./references/common-go-bugs.md), [diagnostic-tools.md](./references/diagnostic-tools.md)
"Sometimes works, sometimes fails"
→ go test -race ./...
→ See [concurrency-debug.md](./references/concurrency-debug.md), [testing-debug.md](./references/testing-debug.md)
"Program hangs / frozen"
→ curl localhost:6060/debug/pprof/goroutine?debug=2
→ See [concurrency-debug.md](./references/concurrency-debug.md), [pprof.md](./references/pprof.md)
"High CPU usage"
→ pprof CPU profiling
→ See [performance-debug.md](./references/performance-debug.md), [pprof.md](./references/pprof.md)
"Memory growing over time"
→ pprof heap profiling
→ See [performance-debug.md](./references/performance-debug.md), [concurrency-debug.md](./references/concurrency-debug.md)
"Slow / high latency / p99 spikes"
→ CPU + mutex + block profiles
→ See [performance-debug.md](./references/performance-debug.md), [diagnostic-tools.md](./references/diagnostic-tools.md)
"Simple bug, easy to reproduce"
→ Write a test, add fmt.Println / log.Debug
→ See [testing-debug.md](./references/testing-debug.md)
请记住: 阅读错误 → 复现 → 测量一项指标 → 修复 → 验证
大多数 Go 漏洞都属于以下情况:未检查错误、nil 指针、忘记取消 context、未关闭资源、竞态条件,或静默吞掉错误。
黄金法则
1. 先阅读错误消息
Go 错误消息很精确。开始其他操作前,先完整阅读:
- 文件和行号 → 直接跳转到对应位置
- 类型不匹配 → 检查函数签名和接口实现情况
- “undefined” → 检查导入、导出名称和构建标签
- “cannot use X as Y” → 检查具体类型与接口
2. 修复前先复现
绝不要靠猜测调试——先复现。务必:
- 编写能捕获漏洞的失败测试
- 确保结果具有确定性
- 隔离出最小失败示例
- 使用
git bisect查找引入问题的提交
3. 不测量就是猜测
性能或并发漏洞绝不能依赖直觉:
- 相信 pprof,而非直觉
- 相信竞态检测器,而非推理
- 相信基准测试,而非假设
4. 一次验证一个假设
每次只改一项,并进行测量和确认。如果一次改三项,你将一无所获。
5. 找到根本原因——不要采取权宜之计
在编写修复方案之前,你必须弄清楚为什么会出现这个 bug。临时补丁只是掩盖症状,缺陷仍然存在,因此会在其他地方再次出现——通常离根因更远,第二次也更难追查。
如果你不理解问题:
- 从症状出发,逆向追踪数据流,直到找到问题源头。
- 质疑自己的假设。 你信任的代码也可能有误。
- 连续追问五次“为什么”。 一直追问,直到找到真正的根本原因。
- 进行更多排查。 多加一些 fmt.Println,多检查输出……
6. 研究整个代码库,而不只是 diff
在指出 bug 或提出修复方案之前,先追踪数据流并检查上游处理。单独看似乎有问题的函数,在上下文中可能完全正确——调用方可能会验证输入,中间件可能会强制执行不变量,周围的代码也可能保证该函数所依赖的条件成立。
- 追踪调用方——谁调用了这个函数,传入的值是什么?可以使用代码搜索工具查找调用位置。→ 参阅
samber/cc-skills-golang@golang-gopls技能,通过接口和嵌入解析实际符号——它能找到间接调用位置,并跳过普通 grep 可能遗漏或错误匹配的无关同名标识符。 - 检查上游验证——调用链前面的输入解析、类型转换或保护子句,可能会使这个“bug”无法触发。
- 阅读周边代码——中间件、拦截器或 init 函数可能会设置该函数所依赖的状态。
**如果上下文降低了问题的严重性,但没有彻底消除问题:**仍然要报告,但应降低优先级,并说明哪些上游保证可以保护它。添加简短的行内注释(例如,// note: safe because caller validates via parseID() which returns uint),以便将推理记录下来,供后续审查者参考。
7. 从简单的方法开始
有时,使用 fmt.Println 进行本地调试确实是正确的做法。只有在更简单的方法无效时,才升级工具。绝不能在生产环境中使用 fmt.Println 进行调试——应使用 slog。
危险信号:你的调试方式有误
如果出现以下任一情况,请停止并返回第 1 步:
- “先快速修复,之后再调查”——根本没有所谓的“之后”。找到根本原因。
- 同时进行多项更改——一次只验证一个假设。
- 不了解原因就提出修复方案——“也许我在这里加个 nil 检查就行……”这是猜测,不是调试。
- 每次修复都会暴露新问题——你在处理症状,真正的 bug 在别处。
- 同一问题尝试修复 3 次以上——你的思维模型有误。重新阅读代码,从头追踪数据流。
- “在我的机器上能运行”——你还没有找出环境差异。
- 归咎于框架、标准库或编译器——这几乎从来都不是 Go 的 bug。先验证自己的代码。
参考文件
-
通用调试方法 — 系统化的 10 步流程:定义症状、隔离复现问题、提出一个假设、进行测试、验证根本原因并防止回归。升级指南:何时从
fmt.Println升级到日志记录、pprof 和 Delve,以及如何避免同时进行多项更改的陷阱。 -
常见 Go Bug — 会导致 Go 代码崩溃的 Bug:空指针解引用、接口 nil 陷阱(类型化的 nil ≠ nil)、变量遮蔽、切片/映射/defer/错误/上下文相关问题、竞态条件、JSON 反序列化意外、资源未关闭。每种情况都附有复现模式和修复方法。
-
测试驱动调试 — 为什么编写一个失败的测试是调试的第一步。涵盖测试隔离技巧、用于缩小失败范围的表驱动测试组织方式、有用的
go test标志(-v、-run、用于不稳定测试的-count=10),以及不稳定测试的调试方法。 -
并发调试 — 竞态条件、死锁、goroutine 泄漏。何时使用竞态检测器(
-race)、如何阅读竞态检测器输出、会掩盖竞态的模式、使用goleak检测泄漏,以及如何分析堆栈转储以寻找死锁线索。 -
性能故障排查 — 代码运行缓慢时的处理方法:CPU 性能分析工作流、内存分析(heap 与 alloc_objects 性能分析,查找泄漏)、锁竞争(mutex 性能分析)和 I/O 阻塞(goroutine 性能分析)。如何阅读火焰图、识别热点函数,以及通过基准测试衡量改进效果。
-
pprof 参考 — 完整的 pprof 手册。如何在生产环境中启用 pprof 端点(并配置身份验证)、性能分析类型(CPU、heap、goroutine、mutex、block、trace)、在本地和远程采集性能分析数据、交互式分析命令(
top、list、web),以及如何解读火焰图。 -
诊断工具 — 用于排查特定症状的辅助工具。GODEBUG 环境变量(GC 跟踪、调度器跟踪)、用于断点调试的 Delve 调试器、逃逸分析(使用
go build -gcflags="-m"查找意外的堆分配),以及用于了解 goroutine 调度的 Go 执行跟踪器。 -
生产环境调试 — 无需停止运行即可调试生产环境中的系统。生产环境检查清单、便于搜索的日志结构、安全启用 pprof(身份验证、网络隔离)、从运行中的服务采集性能分析数据、网络调试(tcpdump、netstat),以及 HTTP 请求/响应检查。
-
编译问题 — 构建失败:模块版本冲突、CGO 链接问题、
go.mod与已安装 Go 版本不匹配、阻止交叉编译的平台专属构建标签。 -
代码审查风险信号 — 代码审查时需留意的潜在 Bug 信号:未检查错误、缺少 nil 检查、并发访问映射、没有明确退出方式的 goroutine,以及循环中的 defer 导致资源泄漏。
交叉参考
- → 识别瓶颈后,参阅
samber/cc-skills-golang@golang-performanceskill,了解优化模式 - → 参阅
samber/cc-skills-golang@golang-observabilityskill,了解用于 Go 运行时监控的指标、告警和 Grafana 仪表板 - → 参阅
samber/cc-skills@promql-cliskill,了解在生产事故调查期间查询 Prometheus 指标 - → 参阅
samber/cc-skills-golang@golang-concurrency、samber/cc-skills-golang@golang-safety、samber/cc-skills-golang@golang-error-handlingskills