vscode 調試技巧|程序不是寫出來的?是調出來的!

常用的調試手段

作爲程序猿的我可太清楚調試的重要性了,有一句話說的很對:程序不是寫出來的,是調出來的。調試的方法很多,比如樸實的日誌打印,打點的計量統計(比如 golang 的 pprof 信息),還有無侵入式的單點調試。

在 c/c++ 我們最常用的是 gdb 調試,這是必備技能。在 golang 裏面,我經常用的是 dlv 調試,用來分析程序的底層邏輯。奇伢的調試姿勢通常有三種:

  1. 先 go build 編譯,出二進制文件,然後用 dlv exec 來調試;

  2. 程序已經跑在測試環境,dlv attach 調試;

  3. 程序出 core 了,dlv core 調試;

個人還是挺習慣這種較爲最原始的方式來調試程序。

避免依賴過重的工具?

IDE 提供了非常方便的調試功能,比如 goland 的調試功能,但 IDE 封裝的過於嚴重,並且調試界面的實現各有不同,雖然提供了便捷,但是它對程序猿幾乎相當於黑盒。一旦遇到點調試的問題,很難梳理清楚。並且當切換環境的時候經常要重新配置複雜的配置。

奇伢個人儘量強避免依賴這些 IDE 的特有的調試功能的,黑盒不透明是一個原因,第二個原因是類似 goland 這種商業付費的軟件,License 經常過期,在換電腦或平臺的時候,各種不同的付費策略導致這些軟件使用很糾結。並且太過依賴它,卻不知 dlv 通用的調試技能,會導致工具的遷移成本過高

那奇伢是一定要沉浸在終端調試的美夢中嗎?

那不是,奇伢不排斥任何工具,只要你能完全掌控它即可。今天奇伢要分享一點關於 vscode 的調試姿勢,個人覺得是比較適合我的預期的:

  1. 很透明,讓用戶有種掌控的感覺;

  2. 姿勢通用,不會讓你只能依賴於 vscode ,還是 dlv 的用法;

  3. 工具全平臺可用,windows,mac,linux ,調試姿勢完全一樣;

vscode 只作爲一個界面,還是最基本的 gdb 或者 dlv 調試,這個過程讓你看得到。

奇伢的調試姿勢

Go 程序用的最多的還是 dlv 調試,現在有了 vscode ,感覺是有了一個新的體驗。本質上還是 dlv 調試。我們先捋一捋調試的思路,按照模式分爲兩大類來講:

  1. 調試二進制文件:先編譯,後調試,對應 launch 調試;

  2. 調試運行進程:調試正在運行的進程,對應 attach 調試;

如果按照代碼位置再區分 local 還是 remote ,那麼姿勢就可以分爲:

  1. 本地 launch 調試:vscode 在本機,代碼在本地,二進制在本地;

  2. 本地 attach 調試:vscode 在本機,代碼在本地,進程在本地;

  3. 遠程 lanuch 調試:vscode 在本機,代碼遠端,二進制在遠端;

  4. 遠程 attach 調試:vscode 在本機,代碼在本地,二進制在遠端;

下面分別舉兩個最典型的栗子,遠程開發 launch 調試和遠程 attach 調試,來看看奇伢是怎麼配置調試的吧。

 1   遠程開發調試 launch

演示的場景:vscode 在本地,代碼在遠端,二進制在遠端。

這種方式本質是先編譯,後調試。先編譯出二進制文件,然後進行運行這個二進制文件進行調試。怎麼得到這個二進制?

有兩種方式:

  1. 讓 vscode 編譯出你的二進制文件,通過配置 task.json 這個文件,定義你的編譯規則;

  2. 還有一種方式,就是純粹靠你自己來編譯出二進制,比如你寫了個 Makefile  或者 go build 出你的二進制;

只要有個二進制,我們就能調試。這個對應了我常用的 dlv exec 的方式。vscode 調試首先創建一個 .vscode/launch.json  的配置文件:

{
    // 自定義名字
    "name""Launch file",
    // 調試的程序類型
    "type""go",
    // 調試類型(調試二進制)
    "request""launch",
    // 調試類型
    "mode""debug",
    // 調試的程序
    "program""${file}"
}

上面的配置好後,打開你的主程序( main.go )文件,給你的文件設置個斷點,點擊左側的運行調試按鈕。就能讓 vscode 先編譯,後調試,並且停頓再斷點出。

vscode 會編譯出一個二進制文件 __debug_binxxx ,然後 debug 這個文件,並且 dlv dap 也會啓動一個 dap server,用於和 vscode 鏈接

示例如圖:

這個太簡單了,幾乎沒有任何障礙。

 2   遠程調試 attach

演示的場景:vscode 在本地,代碼在本地,進程在遠端。 這種場景說白了就是:我代碼在本地,進程在線上。

因爲奇伢是做後端開發的,平時開發的程序都是守護進程,那麼 attach 這種方式是更通用的方式。往往就是進程正在運行,我們再去調試。gdb 和 dlv 都具備 attach 這種能力。這種場景,是經常在調試線上的守護程序來的。

如果是本地終端用這種方式調試:

dvl attach <pid>

假設,當前我們進程跑在線上:

  1. 在某臺測試機器上,程序已經跑起來了,機器上沒有代碼;

  2. 我們本地有版本一致的代碼,用 vscode 打開着;

你想要調試它,怎麼辦?

第一種方法:可以 ssh 到遠端機器,然後 dlv 去調試。對比着本地的代碼設置斷點,進行調試。相對來講比較麻煩。

假設,如果能用本地的代碼加上遠端的 dlv ,無縫聯合起來,同步調試?豈不是完美。

vscode 支持這種方式! 使用的是 dlv 的 dap 功能,遠端機器上用 dlv attach 到對應進程,且開一個 dap server 監聽端口,本地 vscode 去連接這個端口。它們之間的通信使用 DAP 協議走網絡傳輸,從而實現遠程的 attach 調試。

下面來看一下具體演示步驟吧。

 1   步驟一:遠程拉起進程

這個很簡單,後端開發,守護進程纔是最常見的場景。

# 自己的進程自己拉。假設進程號是 7488 
./hello_server

 2   步驟二:dlv dap 服務器

開啓一個 dap 服務器,並且 dlv attach 到對應的進程上,並啓動 dap 服務器;

dlv --headless -l 0.0.0.0:2345 attach 7488 --api-version 2

解釋:

 3   步驟三:vscode 客戶端配置

這個作爲 dap 客戶端,配置和 dlv dap 服務器的聯通即可。

"configurations"[
 {
  // 自定義,名字,看起來有意義就行,用來給你選的;
  "name""Connect to server",
  // 調試的是 go 程序
  "type""go",
  // attach 進程的方式
  "request""attach",
  // 遠程調試
  "mode""remote",
  // 注意!!非常關鍵,這是能否成功設置斷點的關鍵參數。
  "remotePath""{編譯的項目路徑}",
  // dlv server 啓動的端口
  "port": 2345,
  // 遠程主機的 IP
  "host""192.168.56.12"
 }
]

強調 remotePath 這個參數,這個參數非常關鍵,是你能否遠程斷點成功的關鍵。它並不是進程當前的目錄,也不是本地項目的代碼目錄,而是編譯二進制的項目目錄

舉個栗子:加入 hello_server 這個進程是在 /root/code/ 這個目錄編譯的,那麼 remotePath 目錄填的這個。後面 hello_server 放到其他任意目錄運行都和 remotePath 沒關係。

 4   步驟四:運行調試

設置斷點,發一個請求,就可以調試了。演示效果:

斷點技巧

vscode 能打的斷點有三種:

  1. 普通斷點,運行到了就會停住;

  2. 條件斷點,滿足條件纔會停住;

  3. 日誌斷點,運行到了只打印,不停;

 1   Breakpoint

普通斷點,這是最常見的斷點,提前設置到代碼某個位置,運行到了就會停在對應位置。

 2   Conditional Breakpoint

條件斷點。滿足條件纔會斷住,這個可以更精準的調試。這個表達式是語言本身的表達式即可:比如 c++ :

tag == 2

tag 是 c++ 的一個整形變量。

 3   Logpoint

日誌打印,不斷點。很實用的技巧,只要路過就會打印一行信息。適用於不適合暫停調試的程序。比如可以輸入:

result is {result.code()}

result 是 c++ 的一個 class 變量,code 是它的方法。

Debug Console

程序斷點打住之後,我們還可以交互(就和 gdb,dlv 一樣,手動輸入命令),可以輸入命令前綴 -exec 。比如,反彙編:

-exec disassemble

打印寄存器:

-exec print $rip

想知道全部命令,可以 help 一下:

-exec help

總結

  1. 調試的兩大類 launch 調試和 attach 調試,開發過程 launch 模式可能佔多數,但是測試過程,attach 模式可能纔是多數的需求;

  2. 使用 dlv dap 開啓一個 dap server,這樣讓編輯器或者 IDE 都能夠通過網絡介入調試

  3. vscode 調試只是作爲一個客戶端,代碼在本地,程序在遠端,用 vscode 拉通起來,完美體驗;

  4. 遠程 attach 調試其實不需要遠端有代碼哦,這個記住了,remotePath 參數是關鍵;

  5. 除了普通斷點,條件斷點和日誌斷點真的挺有用的;

後記

學會調試,程序學習上手就快,高效的工具纔是生產力。點贊、在看 是對奇伢最大的支持。

奇伢雲存儲 雲存儲深耕之路,專注於對象存儲,塊存儲,雲計算領域。堅持撰寫有思考的技術文章。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/6JKIkTJn28cG66Slwv_TIA