天天看點

使用 vscode 調試 golang 短暫程序

背景

使用 vscode 調試 golang 程式相信大家并不陌生,但當我們要調試的程式有以下特點的話,是不是會變得很棘手?

  • 要調試的程式并不由我們直接觸發
  • 要調試的程式是短暫程序(調試中難以捕獲程序 id)

本文将以 git-hooks(proc-receive)的調試為例介紹一種針對這種場景的調試方案

程式編譯

本文示例代碼位址:

https://code.aone.alibaba-inc.com/agit/git-hooks-demo

當然我們在編譯代碼前要記得關閉編譯器優化:

go build -gcflags='all=-N -l' -o hooks/proc-receive.bin cmd/proc-receive/*.go           

使用 dlv 托管程序的啟動

一般來說我們直接使用的是編譯出的二進制檔案,但在調試場景下,如果能通過某些手段讓程式在真正執行前先“等待”我們的調試器去連接配接,并且在調試器下發一個“開始執行”的指令後才執行代碼邏輯,我們就能實作對這類程序的調試。

幸運的是 dlv 工具就為我們提供了這樣的能力。如下,我們事先在調試器中設定好斷點,然後将 proc-receive 的啟動以 dlv headless server 的形式進行包裝,那麼在該程式被真正喚起之前就會插入一個 dlv 等待調試用戶端的連接配接的啟動暫停!

#!/bin/bash

dlv --log --log-dest hooks/dlv.log --listen=:2345 --headless=true --api-version=2 exec hooks/proc-receive.bin           

注意,使用 dlv 啟動程序時推薦配置 --log 和 --log-dest 參數,否則會幹擾到原程式的 stdout 和 stderr,進而影響程式的正常互動

配置 launch.json

如上,我們通過 dlv headless server 的方式啟動的程式,vscode 自然需要進行配套的一些設定:

{
	// Use IntelliSense to learn about possible attributes.
	// Hover to view descriptions of existing attributes.
	// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
	"version": "0.2.0",
	"configurations": [
		{
			"name": "attach proc-receive",
			"type": "go",
			"request": "attach",
			"mode": "remote",
			"remotePath": "${workspaceFolder}",
			"port": 2345,
			"host": "127.0.0.1"
		}
	]
}           

開始調試

初始化倉庫和 proc-receive 配置

# 初始化倉庫
git init --bare /tmp/demo.git

# 配置被 proc-receive 截獲的引用
cd /tmp/demo.git
# 開始 push-options 支援
git config receive.advertisepushoptions true
# refs/ok will mark command status `ok`
git config --add receive.procreceiverefs refs/ok
# refs/ng will mark command status `ng`
git config --add receive.procreceiverefs refs/ng
# refs/re will mark command status `ok` with a renamed refname
git config --add receive.procreceiverefs refs/re
# refs/ig will ignore the command totally
git config --add receive.procreceiverefs refs/ig

# 配置 git hooks 指向我們工程裡的 hooks 目錄
mv hooks hooks.backup
ln -sf $PROJECTDIR/hooks           

觸發 proc-receive

# repo clone
git clone /tmp/demo.git /tmp/demo
cd /tmp/demo

# add some commit
git commit --allow-empty -m "empty commit on `date`"

# push to trigger proc-receive
GIT_TRACE_PACKET=1 git push origin HEAD:refs/ok/01 HEAD:refs/ng/01 HEAD:refs/re/01 HEAD:master           

使用 vscode 進行調試

執行 git push 後,push 的流程在需要喚起 proc-receive 程序的時候就會 hang 住,等待 dlv 用戶端的連接配接

使用 vscode 調試 golang 短暫程式

此時,使用 vscode 打開代碼工程,在程式中添加斷點(因為是短暫程序,不提前設斷點的話程式一下子就執行完成了),然後切換到調試 tab,選擇 `attach proc-receive`,調試就能夠正常開始了!

使用 vscode 調試 golang 短暫程式