gops 的实现
gops 是一个用来列举和调查当前系统中运行的 Go 进程的工具。
gops 的代码仓库位置: 。这个工具我看到时已经多年没有更新实现了,调试作用也有限。它的功能大多可以用 Go pprof 来做,而且做的更好。在看到其他 Go 开发的监控工具时看到 gops 这份实现。虽然功能简单,不过实现简洁好懂故做一记。
gops 的使用
gops 主要的 3 个作用:
- 列出当前 os 上所有 Go processes 以及这些 Go Process 用的 Go version。比如:
- 通过 pid 查看对应 Go process 的运行信息 (stack, memstat, pprof-cpu 等等)。比如查看对应 Go process 的 stack 信息:
$ gops stack (<pid>|<addr>) gops stack 85709 goroutine 8 [running]: runtime/pprof.writeGoroutineStacks(0x13c7bc0, 0xc42000e008, 0xc420ec8520, 0xc420ec8520) /Users/jbd/go/src/runtime/pprof/pprof.go:603 +0x79 runtime/pprof.writeGoroutine(0x13c7bc0, 0xc42000e008, 0x2, 0xc428f1c048, 0xc420ec8608) /Users/jbd/go/src/runtime/pprof/pprof.go:592 +0x44 runtime/pprof.(*Profile).WriteTo(0x13eeda0, 0x13c7bc0, 0xc42000e008, 0x2, 0xc42000e008, 0x0) /Users/jbd/go/src/runtime/pprof/pprof.go:302 +0x3b5 github.com/google/gops/agent.handle(0x13cd560, 0xc42000e008, 0xc420186000, 0x1, 0x1, 0x0, 0x0) /Users/jbd/src/github.com/google/gops/agent/agent.go:150 +0x1b3 github.com/google/gops/agent.listen() /Users/jbd/src/github.com/google/gops/agent/agent.go:113 +0x2b2 created by github.com/google/gops/agent.Listen /Users/jbd/src/github.com/google/gops/agent/agent.go:94 +0x480
- 操作对应的 Go process 比如:
gops 的实现
列出当前 OS 中的 Go Process
要列举当前 OS 中所有 Go Porcess 只需要 2 个步骤: - 列出 OS 上所有的 processes - 判断出对应的 process 是否是 Go Process 并且分析出对应的 Go verison
列出 OS 上所有的 processes ,这个步骤可以用 gopsutil 来实现。接下来只要解析出对应的进程用什么 Go 版本来编译的就可以得出 gops
的 Go processes list。判断方法为,通过 Go 系统库的 debug/buildinfo
来解析对应可执行文件。关键代码如下:
import "debug/buildinfo"
// path 为 gopsutil 枚举到的 Go process filename
func goVersion(path string) (string, error) {
info, err := buildinfo.ReadFile(path)
if err != nil {
return "", err
}
return info.GoVersion, nil
}
这里要注意的是:Go 1.18 以上才提供 debug/buildinfo
的这个功能。如果早于 Go 1.18 需要用一个第三方实现 rsc.io/goversion/version
。
获取调试信息和操作对应 Go Process
要实现调试和设置对应 Go Process 的功能有一个前提:对应的 Go Process 必须包含 gops 的 agent 。否则无法调试的,比如下面这段 code 需要被引入对应的调试的 Go Process:
import (
"log"
"time"
"github.com/google/gops/agent"
)
func main() {
if err := agent.Listen(agent.Options{}); err != nil {
log.Fatal(err)
}
time.Sleep(time.Hour)
}
这个 gops/agent
会在对应的 Go process 里监听一个 port 默认会在 127.0.0.1
上。gops
的命令在调试和操作进程时,会通过 pid 找到对应的通讯 port 用 tcp 连接过去通讯。来获取调试信息以及操作对用的 process 行为。
这个做法其实和 Go 的 pprof
类似,只是这里用 127.0.0.1
并且是用 tcp 本地连接。所有相对 pprof
安全些。
当然这点用 Go pprof 也可以做到,所以 gops
没有什么太大的实际用处。只能参考些实现代码。