开发中进行调试能够帮助我们快速定位问题,同时也可以帮助我们梳理代码逻辑。相比日志输出,调试更能够在项目早期提升开发效率。在使用 golang 开发的前两年,我主要使用 goland 进行开发,goland 的调试功能是其相比于 vscode 的一大优势。在开发过程中,我们所开发项目通常不会运行本地或者开发机,可能是运行在一个远程集群中,依赖环境配置以及其他服务,goland 能够很方便的实现在本地开发,然后将程序拷贝到服务器,并对其进行调试。

golang 只需要将远程服务器配置位一个 target,就可实现本地开发类似的效果。

本文将介绍 vscode 借助其开发调试和任务特性,配置 launch.json 和 task.jsoan 文件实现golang 程序的一键远程调试的功能,执行调试,vscode 帮助完成所有以下步骤。

  1. 编译程序,下面使用uvmt-agent进行演示。
  2. 将编译好的程序和调试工具 dlv 拷贝到需要调试的机器上。
  3. 在需要调试的机器上运行 dlv 通过 DAP 运行 headless server。
  4. vscode 连接远程机器上调试服务,开始调试。

task 配置

vscode 提供 task 功能,用户可以定义一些常用的 task 任务,通过命令快速执行。vscode 首先会扫描工作区,自动生成一些 task,用户的自定义 task 最终会保存在.vscode/task.json文件中. 我们通过以下配置实现上述 1、2、3 步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{
"version": "2.0.0",
"tasks": [
{
// 1. 编译程序,需要指定-gcflags=all="-N -l"禁用编译优化和內连
"type": "shell", // 可以使用通用shell类型,也可以使用go类型
"label": "go: build uvmt-agent: disable Inlining and optimizations", // lable是任务唯一标识
"command": "go",
"args": [
"build",
"-o",
"/tmp/uvmt-agent",
"-gcflags=all=\"-N -l\"",
"${workspaceFolder}/v2v/cmd/uvmt-agent"
],
"problemMatcher": ["$go"],
"group": "build",
"detail": "cd /data/dg/code/huanghews/hhkits/v2v/cmd/uvmt-agent; go build uvmt-agent"
},
{
// 2. 将编译好的uvmt-agent以及golang调试工具dlv拷贝到远程服务器
"type": "shell",
"label": "scp uvmt-agent and dlv to remoteServer",
"command": "scp",
"args": [
"/tmp/uvmt-agent",
"/data/dg/go/bin/dlv",
"root@${input:remoteServer}:/tmp"
],
"dependsOn": ["go: build uvmt-agent: disable Inlining and optimizations"] // 执行此任务之前,需要执行编译
},
{
// 3. 在远程服务器上运行dlv dap headlease server
"type": "shell",
"label": "run remote dlv headless server",
"command": "ssh",
"args": [
"root@${input:remoteServer}",
"cd /tmp;./dlv dap --listen=:12345"
],
"dependsOn": ["scp uvmt-agent and dlv to remoteServer"], // 同样,需要先执行步骤2
"isBackground": true, // 因为dlv需要保持在后台运行
"problemMatcher": [
{
"pattern": [
{
"regexp": ".",
"file": 1,
"location": 2,
"message": 3
}
],
"background": {
"activeOnStart": true,
"beginsPattern": ".",
"endsPattern": "."
}
}
] // 配置该problemMatcher十分重要,告诉vscode 前置任务已经执行完成,可以执行调试了
}
],
"inputs": [
{
// 通过input可以实现remoteServer地址的配置
"id": "remoteServer",
"description": "remote server ip address",
"default": "192.168.100.3",
// vscode ui会提示输入远程服务地址,并带上默认值
"type": "promptString"
}
]
}

我们可以直接运行此任务,验证 dlv 是否在远程服务器上运行。

lanuch 配置

通过安装Go extension插件,vscode 可是对 golang 程序的调试.简单的本地调试,直接打上断点,就可以直接调试,复杂的调试需要创建launch.json进行配置,同样该配置文件也会保存在.vscode目录.通过以下配置,我们可以连接到远程运行的 dlv server,vscode 进入调试中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"version": "0.2.0",
"configurations": [
{
"name": "uvmt-agent-remote-debugger",
"type": "go",
// 通过launch方式,可以不需要dlv运行调试的程序
// launch方式需要指定program的绝对路径
"request": "launch",
"mode": "exec",
"port": 12345,
"host": "10.76.197.214",
// 注意dlv的版本,旧版本不支持dap模式
"debugAdapter": "dlv-dap",
"program": "/tmp/uvmt-agent",
// 调试之前,等待该任务运行结束
"preLaunchTask": "run remote dlv headless server",
"showLog": true
}
]
}

所有配置已经完成。我们看一下效果。

总结

借助 vscode 的调试和任务特性,我们可以提高开发效率,并且可自定义程度非常高,你需要根据每个项目的场景,对配置进行适当调整。 出于网上相关配置用例很少,我写了这片总结,希望本文对你有帮助,如果有更优雅的方式,欢迎讨论。

参考

  1. vscode-golang 调试配置
  2. vscode task 配置