使用 dlv (Delve) 工具调试 Golang 程序。它是理解Go程序时 GDB 调试器的有效替代品。
Install
# go install github.com/go-delve/delve/cmd/dlv@latest
sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
apk add go
export GOPROXY=https://goproxy.cn,direct
export CGO_ENABLED=1
export GO111MODULE=on
go install github.com/go-delve/delve/cmd/dlv@latest
ls -lah /root/go/bin/dlv
go version
dlv version
Use
# 开始
dlv debug ./cmd/main.go
dlv exec /opt/iam/bin/iam-apiserver
# 如果希望二进制文件被调试,在编译二进制文件时需要关闭内联优化:
# go build -gcflags=all="-N -l"
# 如果不希望二进制文件被调试,则可以使用以下编译选项:
# go build -ldflags "-s -w" # -s: 去掉符号信息;-w: 去掉 DWARF 调试信息。
dlv core <executable-file> <core-file> # 使用core文件启动调试,这种方式可以找出可执行文件core的原因
# 查看源码组
(dlv) list main.main # 定位 main包main 函数
(dlv) list main.init # 定位 main包init
(dlv) funcs fib # 搜索函数
(dlv) vars main # 查看 main包变量
# 添加断点
(dlv) break ./main.go:10 #b ./main.go:10
(dlv) b main.main
(dlv) b main.init
(dlv) list ./main.go:10 #l ./main.go:10
(dlv) breakpoints #bp # 查看设置了哪些断点
# 删除断点
(dlv) clear 1 # 删除标识ID为1的断点
(dlv) clearall # 清除所有断点
# 调试断点(一旦设置断点,能用list命令查源代码)
(dlv) continue #c # 运行到下一个断点处
(dlv) next #n # 运行到源代码下一行
(dlv) step #s # 进入到函数调用的内部
(dlv) stepout #so # 跳出函数调用内部
(dlv) restart #r # 在程序终止或准备重新开始调试时,重启程序,断点不丢失
# 退出调试
(dlv) exit # quit # q
我这里要查找的是使用
https://github.com/eddycjy/fake-useragent
后,一开始很卡的原因(main函数前),通过以下函数定位到了这个包
GODEBUG=inittrace=1
进而找到了
// https://github.com/eddycjy/fake-useragent/blob/master/b.go#L30
var defaultBrowser = NewBrowser(Client{
MaxPage: setting.BROWSER_MAX_PAGE,
Delay: setting.HTTP_DELAY,
Timeout: setting.HTTP_TIMEOUT,
}, Cache{})
func NewBrowser(client Client, cache Cache) *browser {
maxPage := setting.GetMaxPage(client.MaxPage)
delay := setting.GetDelay(client.Delay)
timeout := setting.GetTimeout(client.Timeout)
b := browser{
Client: Client{
MaxPage: maxPage,
Delay: delay,
Timeout: timeout,
},
Cache: Cache{
UpdateFile: cache.UpdateFile,
},
}
return b.load()
}
func (b *browser) load() *browser {
fileCache := cache.NewFileCache(cache.GetTempDir(), fmt.Sprintf(setting.TEMP_FILE_NAME, setting.VERSION))
fileExist, err := fileCache.IsExist()
if err != nil {
log.Fatalf("fileCache.IsExist err: %v", err)
}
// handle cache.
if b.UpdateFile == false {
var (
isCache bool
cacheContent []byte
m map[string][]string
)
if fileExist == true {
cacheContent, err = fileCache.Read()
if err != nil {
log.Fatalf("fileCache.Read err: %v", err)
}
isCache = true
} else {
rawCache := cache.NewRawCache(setting.CACHE_URL, fmt.Sprintf(setting.TEMP_FILE_NAME, setting.CACHE_VERSION))
rawResp, rawExist, err := rawCache.Get()
...
而后发现
// https://github.com/eddycjy/fake-useragent/blob/master/setting/setting.go#L13
const (
VERSION = "0.2.0"
BROWSER_URL = "https://developers.whatismybrowser.com/useragents/explore/%s/%s/%d"
BROWSER_MAX_PAGE = 5
BROWSER_ALLOW_MAX_PAGE = 8
CACHE_VERSION = "0.2.0"
CACHE_URL = "https://raw.githubusercontent.com/EDDYCJY/fake-useragent/v0.2.0/static/"
HTTP_TIMEOUT = 5 * time.Second
HTTP_DELAY = 100 * time.Millisecond
HTTP_ALLOW_MIN_DELAY = 100 * time.Millisecond
TEMP_FILE_NAME = "fake_useragent_%s.json"
TEMP_FILE_TEST_NAME = "fake_useragent_test_%s.json"
)
推荐使用这个包:https://github.com/brianvoe/gofakeit