不能直接用 fmt.Printf("%+v", obj),因为其对嵌套结构体、指针、接口、循环引用等支持差:字段易截断、指针地址不清晰、接口底层类型不可见、自引用会panic;spew是专为调试设计的深度打印工具,可安全展开全层级、保留类型信息、循环检测可开关。

为什么不能直接用 fmt.Printf("%+v", obj)?
因为 fmt 对嵌套结构体、指针、接口、循环引用等场景处理很弱:字段值可能被截断,指针地址暴露不清晰,接口底层类型不可见,遇到自引用会 panic。而 spew 是专为调试设计的深度打印工具,能安全展开所有层级,保留类型信息,且默认禁用循环检测(可开关)。
怎么安装和基础使用 spew?
执行 go get github.com/davecgh/go-spew/spew 即可。最常用的是 spew.Dump() 和 spew.Sdump() —— 前者直接输出到 os.Stderr,后者返回字符串,适合记录日志或做断言对比。
-
spew.Dump(user):调试时快速看全貌,带颜色、缩进、类型前缀,支持 Ctrl+C 中断不影响程序 -
log.Printf("user: %+v", spew.Sdump(user)):避免日志里混入 ANSI 色彩码(Sdump默认不着色) - 想关闭循环保护?用
spew.Config.DisableCircularDetection = true,但仅限明确知道无环时启用
如何控制输出精度,避免日志爆炸?
spew 默认展开全部字段,对大 slice 或 map 很容易刷屏。关键配置项都在 spew.Config 上:
-
spew.Config.MaxDepth = 3:限制递归深度,3 层后显示[...] -
spew.Config.Indent = " ":改缩进字符,适配你的日志格式 -
spew.Config.ContinueOnMethod = false:禁止调用结构体方法(防止副作用),默认是true - 敏感字段不想打?用
spew不提供字段过滤,得靠结构体加spew:"skip"tag,例如:Token string `spew:"skip"`
在 HTTP handler 里打印请求结构体要注意什么?
别直接 spew.Dump(r) —— *http.Request 包含 Body io.ReadCloser,spew 会尝试读取并耗尽它,导致后续 r.Body 为空。正确做法是只打你关心的字段:
立即学习“go语言免费学习笔记(深入)”;
spew.Dump(struct{ Method, URL, Header map[string][]string }{r.Method, r.URL.String(), r.Header})- 或者提前复制
Body(用io.ReadAll+io.NopCloser),但仅限调试,线上禁用 - 注意
context.Context字段在spew下会显示内存地址,基本无意义,建议跳过
真正麻烦的是深嵌套的 ORM 模型或 gRPC message,它们常带私有字段、未导出字段、sync.Mutex 等,spew 虽能打印,但输出可能冗长且干扰判断——这时候不如手动选几个关键字段拼字符串。



















