recover日志必须包含时间戳、panic值和完整堆栈;需用time.Now()打时间戳、runtime/debug.Stack()获取原始栈并转为字符串,截断防超长,HTTP中间件中还需拼入request ID、method、path、client IP等上下文。

recover日志必须包含时间戳、panic值和完整堆栈
生产环境里只打印recover()返回的interface{}值(比如"index out of range")毫无意义——你根本不知道它在哪一行触发、上下文是什么、调用链有多深。必须搭配runtime/debug.Stack()获取原始栈数据,并用time.Now()打上精确时间戳。
常见错误现象:log.Printf("panic: %v", r)这种写法漏掉所有位置信息,排查时只能靠猜;或者用fmt.PrintStack()直接输出到stderr,无法接入统一日志系统(如Loki、ELK)。
- 堆栈必须在
recover()后立即调用debug.Stack(),延迟哪怕一行都可能因其他defer执行而污染栈帧 -
debug.Stack()返回[]byte,需用string()转成字符串再拼接,不能直接传给log.Printf的%s - 生产环境建议截断栈长度(如
string(debug.Stack()[:min(len(debug.Stack()), 4096)])),避免单条日志超10MB拖垮日志采集器
HTTP中间件里recover日志要带请求上下文
Web服务中,单个请求panic若不记录request ID、method、path、client IP,等于把故障埋进黑盒。中间件层的recover必须从*http.Request里提取关键字段,和panic日志拼在一起。
典型场景:用户上传一个畸形JSON,解析时panic,但日志里只有"invalid character ',没ID、没路径、没traceID,你连重放都做不到。
立即学习“go语言免费学习笔记(深入)”;
诊断并恢复通过 SSH 隧道连接的 OpenClaw 节点。用于解决配对必需错误、隧道冲突、远程端点错误以及 SSH 目标配置错误等问题。
- 优先从
r.Context().Value()取已注入的requestID(如用gorilla/handlers或自定义中间件注入) - fallback到
r.RemoteAddr和r.URL.Path,至少保证基础定位能力 - 避免在
recover块里调用可能panic的函数(如r.Header.Get()前不检查r.Header是否为nil)
recover后不能复用已损坏的局部变量
日志格式再规范也没用,如果recover之后还试图读取越界slice、向已close的channel发消息、或继续用panic前已处于未定义状态的map,大概率二次panic,新日志覆盖旧日志,原始问题彻底丢失。
常见错误现象:recover捕获了panic: send on closed channel,但后续代码仍调用ch ,导致日志里只看到第二个panic,第一个永远查不到。
- recover后应立即清理资源(如
close()文件句柄、unlock()互斥锁),而不是继续业务逻辑 - 禁止对panic前涉及的变量做任何读写,除非显式校验(如
if myMap != nil { ... }) - 推荐模式:recover → 记录日志 →
return(或返回error让上层处理),不“硬撑”往下跑
多goroutine场景下每个入口必须独立recover
主线程加了defer+recover,对go func(){ panic() }()完全无效。子goroutine panic会静默退出,连接不关闭、事务不回滚、监控无报警,等你发现时可能已积压数万条失败任务。
典型场景:后台定时任务用errgroup.Group并发拉取数据,其中一个goroutine因第三方API返回空数组导致索引越界panic,整个Group.Wait()卡死,日志里却一片空白。
- 每个goroutine启动处必须手动加
defer func(){ if r := recover(); r != nil { log... } }() - 用
errgroup.Group时,它的Go()方法内部已封装recover,但你要确认版本≥v1.0.0(旧版不保证) - 避免在goroutine里直接调用未包装的第三方库函数,尤其那些可能panic的解析类库(如
json.Unmarshal裸用)
最易被忽略的一点:recover日志里的堆栈是当前goroutine的快照,但它不包含其他goroutine的状态。线上遇到诡异的资源泄漏或死锁,别只盯着panic日志——得结合pprof的goroutine dump和mutex profile交叉验证。

















