以下文章來源于大愚Talk ,作者大愚Talk
delve 的漢語意思是:鉆研、探索;用這個(gè)來命名一個(gè)debug工具還是非常的形象。
本文主要介紹該工具的安裝與常用使用方法。是一個(gè)step-by-step的文章。目標(biāo)是幫助大家學(xué)會(huì)如何使用 delve 來debug自己的代碼。
安裝
官網(wǎng)的安裝文檔地址:
https://github.com/go-delve/delve/tree/master/Documentation/installation
我再重復(fù)下如何在 mac 上進(jìn)行安裝。
首先 xcode-select --install 把依賴的編譯工具鏈安裝一下。
然后通過下面的命令即可完成
$ go get github.com/go-delve/delve/cmd/dlv
這里有個(gè)注意點(diǎn),大家如果使用modules的方式來管理項(xiàng)目,應(yīng)該知道安裝依賴包也是上面這個(gè)命令。所以執(zhí)行上面的命令時(shí),請(qǐng)確保自己不是在一個(gè)go modules的路徑下。
到此,安裝工作就可以完成了,可以在終端執(zhí)行,可以看到如下畫面:
? /Users/dayu >dlv version
Delve Debugger
Version: 1.4.0
Build: $Id: 67422e6f7148fa1efa0eac1423ab5594b223d93b $
命令介紹
用中文來翻譯下命令的含義。
Usage:
dlv [command]
Available Commands:
attach 可以用來對(duì)一個(gè)正在運(yùn)行的進(jìn)行進(jìn)行調(diào)試.
connect 連接到headless調(diào)試器.
core 用來調(diào)試core文件.
dap [EXPERIMENTAL] 啟動(dòng)一個(gè)Debug Adaptor Protocol (DAP)的TCP服務(wù)器來通信.
debug 在當(dāng)前包或者指定的包編譯并debug程序.
exec 如果你已經(jīng)編譯好了二進(jìn)制,可以用該命令啟動(dòng)調(diào)試.
help 幫助命令.
test 可以用來測(cè)試自己編寫的測(cè)試源碼文件.
trace 編譯并跟蹤程序.
dlv 的命令非常多,主要介紹下 debug 與 attach 的使用。其它命令大家可以嘗試下,不過一般用的也非常少!dlv test 這個(gè)也非常有用,不過使用跟debug差不多。
使用
下面將主要介紹這 debug 與 attach 如何使用,這兩個(gè)命令其實(shí)主要面對(duì)兩種使用場景。
- 用 Golang 寫了一個(gè)命令行程序,想要debug一下;
- 寫了一個(gè) Grpc 或者 Http 服務(wù),運(yùn)行的進(jìn)行進(jìn)行debug;
進(jìn)入調(diào)試后,他們的命令非常相似,下面開始我們的 debug 之旅。
Debug Main包程序
先來看直接使用 debug 來調(diào)試代碼。調(diào)試的代碼樣例:

debug調(diào)試代碼
此時(shí)在終端進(jìn)入該文件所在路徑,然后執(zhí)行
dlv debug
然后會(huì)成功進(jìn)入 delve 提供的debug交互界面,如下圖所示。

debug交互
圖中展示了三個(gè)非常常用的命令。來分別解釋下。
- b main.main
這個(gè)命令的全拼是:break main.main 用來設(shè)置斷點(diǎn)的。除了這種寫法,常用的還有使用行號(hào)來設(shè)置斷點(diǎn) b 9。
- bp
這個(gè)命令是用來查找已經(jīng)設(shè)置的斷點(diǎn)的。

斷點(diǎn)查看
查看已經(jīng)設(shè)置的斷點(diǎn)常常一個(gè)目的是用來尋找 clear 可以清除哪一個(gè)斷點(diǎn)。
- c
該命令是讓程序運(yùn)行起來。遇到設(shè)置的斷點(diǎn)會(huì)停止。
上面只是非?;A(chǔ)的三個(gè)命令,我們?cè)賮砝^續(xù)往下走。繼續(xù)看這張執(zhí)行示例圖

調(diào)試
這張圖中的命令,都是非常常用的調(diào)試命令,來一起看看作用
- restart
這個(gè)命令的主要作用就是一輪debug完成了,重新開始下一輪,上一次設(shè)置的斷點(diǎn)會(huì)依然有效
- n
這是執(zhí)行下一步,也就是代碼的下一行。它就是一行一行的往下,不會(huì)陷入內(nèi)部去
- s
該命令注意與 n 的區(qū)別,它是進(jìn)入某個(gè)函數(shù)的內(nèi)部,源碼函數(shù)也能夠跟蹤進(jìn)去,非常有利于我們學(xué)習(xí)。但是對(duì)于 goroutine 執(zhí)行的函數(shù)你是無法進(jìn)入的。這也很好理解,因?yàn)樗膱?zhí)行時(shí)機(jī)不可知。
- p
這個(gè)是debug過程中非常重要的一個(gè)命令,打印變量的值。也是學(xué)習(xí) go 語言的一個(gè)利器,圖中可以看到一個(gè) channel 初始化之后的內(nèi)部結(jié)構(gòu)體。這對(duì)我們理解源碼非常有幫助。
下面的命令圖中沒有演示,但覺得有必要說一下。
- so
如果用了 s 陷入到內(nèi)部函數(shù),可以快速使用該命令跳出來,回到進(jìn)入點(diǎn)。
- gr and grs
這兩個(gè)命令是用來查看 groutine 的。
他還有非常多的命令。我們可以在使用過程中隨時(shí)使用 help 來進(jìn)行查看。文末我也放了一張所有命令圖的翻譯。
Debug運(yùn)行的進(jìn)程
對(duì)于運(yùn)行中的進(jìn)程,主要說明下如何進(jìn)入 debug 交互界面,進(jìn)入后的操作與上面是一樣的。
假如我們有一個(gè) http 的進(jìn)程在運(yùn)行,看一下如何進(jìn)行 debug。示例代碼如下:
func main() {
http.HandleFunc("/", Hello)
http.ListenAndServe(":8080", nil)
}
func Hello(w http.ResponseWriter, r *http.Request) {
a := "test"
fmt.Println(a)
time.Sleep(3 * time.Second)
fmt.Fprint(w, "Hello World")
}
將這個(gè) demo 給運(yùn)行起來,然后找到他的進(jìn)程號(hào)。執(zhí)行下面的命令:
dlv attach {pid}
這個(gè) pid 就是當(dāng)前進(jìn)程的進(jìn)程號(hào)。
使用該方式要注意:設(shè)置完斷點(diǎn)后記得用 c 讓進(jìn)程處于運(yùn)行狀態(tài),否則對(duì)于 http 或者 grpc 的程序,沒有辦法繼續(xù)接受請(qǐng)求,進(jìn)而無法進(jìn)入測(cè)試。

參考資料
[1] https://github.com/go-delve/delve