概述
写代码容易,调代码难,这对于写了很多代码的人来说都是很有感触的一个事情。在 Go 中更是如此,因为 Go 不像 Python 那么动态,像一些 Web 框架(例如 Flask),出现异常的时候你甚至可以直接在浏览器或者控制台直接调试,而且还给你保留了上下文信息,简直不要更爽。但是 Go 里面就没有那么舒服了,当然,在平时开发的时候我们可以在本地单步调试,但是,如果程序跑在后台或者常规测试的时候,就需要一些更加方便的工具来支持了,不然我们就只有日志可以用来定位问题了。
在 Go 里面,其实工具没有很多,除了底层一些的 GDB 之外,可能用得比较广的就剩下 delve 了,我之前也介绍过:使用 delve 远程 debug Go 应用,但是比较简单,实操性不那么高,所以这里又稍微扩展了一下,介绍容器以及一个已经在运行的程序可以怎么操作。
容器环境下使用
[root@liqiang.io]# cat Dockerfile
FROM golang:1.17
RUN go get github.com/go-delve/delve/cmd/dlv
ADD . /go/src/github.com/liuliqiang/go-demos
WORKDIR /go/src/github.com/liuliqiang/go-demos
RUN make server
# Final stage
FROM busybox:glibc
COPY --from=0 /lib/x86_64-linux-gnu/libdl.so.2 /lib/libdl.so.2
COPY --from=0 /go/bin/dlv /home/liqiang/
COPY --from=0 /go/src/github.com/liuliqiang/go-demos/.build/server /home/liqiang/
EXPOSE 2345 9000
WORKDIR /home/liqiang
CMD ["/home/liqiang/dlv", "--listen=:2345", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", \
"/home/liqiang/server", "--", "-iden", "grpc-server"]
这样,当你运行起来这个程序之后,你就拥有了一个可以直接调试的服务器了,然后你就可以通过 Goland 远程调试了。
运行时注入
前面容器环境的示例是直接通过 dlv 启动,这个不具有通用性,更常见的场景是一个程序运行,然后发现有一些异常之后,我们再打开调试器注入调试,dlv 当然也是可以如此,但是需要注意的是,你必须地加 gcflags
标记编译你的代码,不然调试器是调试不了的,因为很多信息都被抛弃掉了。
[root@liqiang.io]# go build -gcflags="all=-N -l" -o /home/liqiang/server
[root@liqiang.io]# /home/liqiang/server # 运行程序
[root@liqiang.io]# ps aux | grep server # 获取程序的 pid
root 299664 0.0 0.0 18024 2748 ? Ss 18:41 0:00 bash -c /home/liqiang/server
注入程序 debug:
[root@liqiang.io]# dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach 299664
这样调试服务器就算是运行起来了。
Goland 连接远程调试
直接在 Goland 中配置 Host 和 Port 即可,操作步骤为选择项目右上角的设置:
图 1:Config Debug |
---|
然后在源代码中选择这个 “Go Remote” 调试器进行调试:
图 2:Add Remote Debugger |
---|
在右侧的窗口中输入 Host 和 Port:
图 3:Add Debug Server |
---|
参数含义
参数 | 说明 | 默认值 |
---|---|---|
--accept-multiclient |
可以多个客户端同时接入 | |
--api-version |
使用的 API 版本,这个版本一定要匹配 | 1 |