不依赖 go ,最小二进制把 pprof 转 svg 的探索
由来
内部同事做了个采集业务 pprof 的功能,发现工具镜像非常臃肿,带了个 golang 出去。用的是 go-torch 把 curl -o /debug/pprof/profile
采集的文件转成 svg ,转换的日志里发现它命令行调用了 go tool pprof
,而且 go-torch
我看仓库已经不维护了。
尝试
一个是涉及到迭代解决安全,另一个 golang 已经 go 自举了,把 go tool pprof
的 pprof
命令抠出来直接用就行了,甚至都不需要 golang 环境了,搜了下发现实际 go tool pprof
就是仓库 google/pprof。
分析
go-torch
转换的命令如下
1 | go-torch xxx-profile-20240416110934.pg.gz -f 1.svg |
浅显的看了下它的源码,发现它是把 pprof 的 raw 格式输出,按照 pprof 的字节流格式解析的,就是 state funcnames samplenames records
那些,然后调用 flamegraph
perl 脚本转 svg 的。
1 | // https://github.com/uber-archive/go-torch/blob/master/renderer/flamegraph.go#L37 |
如果单纯转 svg,pprof 工具就可以,它转 svg 会先转 dot 格式,然后 exec 调用 graphviz
包下的 dot 命令。
dot 命令要包管理安装,并且很多依赖,看看有没有 golang 的实现。谷歌搜索 golang dot to svg
看到了第一个仓库 goccy/go-graphviz,大致看了下 readme.md ,发现它不依赖 graphviz
并且提供了一个 dot 的命令实现。测试下:
1 | go install github.com/google/pprof@latest |
测试转 svg:
1 | pprof -svg -seconds 30 http://xx.xxx.0.84:xxxx/debug/pprof/profile > test.svg |
发现报错,查看了下 pprof 的源码:
1 | // https://github.com/google/pprof/blob/26353dc0451f29f7b9cdade98377a016779b8527/internal/driver/commands.go#L385-L408 |
发现是把 dot 格式的字节流给 dot -Tsvg
的 stdin ,dot 命令会自动把流输出到标准输出,然后 pprof 会把 dot 输出的字节流捕获,上面的报错就是 golang 的 dot 有问题。看了下 dot 的源码,发现 -o 选项是必须的,下面是改过的 diff:
1 | 18c18 |
编译后替换了,发现可以转换成 svg 了,但是还有个问题,会输出 Saved profile in /root/pprof/pprof.main.samples.cpu.001.pb.gz
发现会把 tmp 文件存在这里,可以通过设置变量 PPROF_TMPDIR
指定 tmp 文件路径,但是 pprof 没有任何选项参数删除这个 tmp 文件,提了 issue 直接给我关了。
其实也可以扣 pprof 源码拼 go-graphviz
库源码,这样一键或者 golang 函数内采集指定参数转 svg ,但是这块功能目前还没长期定型下来,暂时还是最小的 pprof + dot