Devle是一個非常棒的golang 調試工具,支持多種調試方式,直接運行調試,或者attach到一個正在運行中的golang程序,進行調試。
線上golang服務出現問題時,Devle是必不少的在線調試工具,如果使用docker,也可以把Devle打進docker鏡像里,調試代碼。
安裝Devle非常簡單,直接運行go get 即可:
go get -u github.com/derekparker/delve/cmd/dlv
使用Delve運行我們的main.go
dlv debug ./main.go
安裝后直接運行dlv將會看到如下信息:
上面列舉了dlv的一些命令,其中常用的有如help、attach、core、debug、trace、version等。
dlv help:上面的信息只是列出了命令列表,具體使用方法沒有給出,這里可以運行dlv help查看具體命令的使用方法。也可以運行dlv help help查看help命令的使用說明。
例如:查看core命令使用說明。
dlv version:查看dlv工具版本信息
進入調試模式的幾種方法:
1、dlv attach pid:類似與gdb attach pid,可以對正在運行的進程直接進行調試(pid為進程號)。
2、dlv run|debug:run命令已被debug命令取代,運行dlv debug test.go會先編譯go源文件,同時執行attach命令進入調試模式,該命令會在當前目錄下生成一個名為debug的可執行二進制文件,退出調試模式會自動被刪除。
3、dlv exec executable_file:直接從二進制文件啟動調試模式。
4、dlv core executable_file core_file:以core文件啟動調試,通常進行dlv的目的就是為了找出可執行文件core的原因,通過core文件可直接找出具體進程異常的信息。
dlv trace:該命令最直接的用途是可以追蹤代碼里函數的調用軌跡,可通過help查看其調用方式。
如下源代碼,main函數里每隔1秒執行一次Afunc函數,現用trace命令跟蹤其調用軌跡。
正式調試開始,為演示dlv的調試命令,這里寫了一個簡單的測試程序:啟動兩個協程對變量進行處理,然后輸出處理后的結果。
進入調試模式后,同樣可以執行help查看所有的命令。
大部分命令和gdb類似,break [name] :設置斷點,當需要設置多個斷點時,為了斷點可識別可進行自定義命名。進入調試模式后先打斷點,b test.go:14,然后執行c(類似於gdb的run)運行到斷點處。
bp:查看所有斷點。
on :當運行到某斷點時執行相應命令,斷點可以是名稱(在設置斷點時可命名斷點)或者編號,例如on 1 p a表示運行到斷點1時打印變量a。
condition :有條件的中斷斷點,當expression為true時指定的斷點將被中斷,程序將繼續執行。
next|step:逐行執行代碼,區別和gdb類似,next遇到函數調用時不會進入該函數,step則會進入函數,如果需要查看函數的具體執行過程則用step,否則用next,調試過程中一般這兩個命令會結合使用,對於用戶自定義的函數可能需要進入函數內部查看每步執行情況,對於系統函數則沒有必要。
step-instruction |si:單步單核執行代碼,如果不希望多協程並發執行可以使用該命令,這在多協程調試時極為方便。
stepout:當使用s命令進入某個函數后又想退出時可用此命令。
args:查看函數參數,調試時可以用此命令查看被調用函數所傳入的參數值。
locals:查看所有局部變量,locals var_name:查看具體某個變量,var_name可以是正則表達式。
clear:清除單個斷點;clearall:清除所有斷點。
list:打印當前斷點位置的源代碼,list后面加行號可以展示該行附近的源代碼,如list test.go:10將會展示test.go文件第10行附近的代碼,值得注意的是該行必須是代碼行而不能是空行。
bt:打印當前棧信息。
frame:切換棧。
regs:打印寄存器內容。
go語言的優勢就是它的協程,為演示多協程下如何調試go進程,對Func函數做如下改動,增加一個for死循環,每休眠一秒輸出變量a。
goroutines:顯示所有協程。編號為1的是主協程,編號為5、6的為自己啟動的協程。
goroutine:協程切換。dlv默認會一直在主協程上執,為打印Func函數中的臨時變量a,需要進行協程切換,先執行goroutine 5表示切換到5號協程上,然后bt命令查看當前協程的棧狀態,執行frame 3 locals切換到3號棧上並打印棧上的變量。
sources:打印所有源代碼文件路徑。
source:執行一個含有dlv命令的文件,source命令允許將dlv命令放在一個文件中,然后逐行執行文件內的命令。
threads:顯示所有線程,thread:線程切換,這兩個命令與goroutines、goroutine類似,不過在go語言中一般很少使用。
trace:類似於打斷點,但程序運行到該處時不會中斷而是繼續執行,同時會輸出一行提示信息。
總結:
利用調試工具進行代碼流程分析固然是一種很好的手段,但是在實際項目開發中最好在代碼里多加一些有意義的log輸出,在遇到問題時能快速定位分析。