使用 VSCode 调试 Golang

[译] 使用 VSCode 调试 Golang

原文来自于: vscode-go

1、安装 Delve

有两种安装 Delve 的方式:

  • 支持命令Go: Install/Update Tools 选择dlv, 安装/更新 delve

(: 文章中提到的执行命令, 并不是在终端中执行,而是在VS Code 命令面板中执行, 打开方式:查看-> 命令面板)

windows

go get -u github.com/go-delve/delve/cmd/dlv

linux

方式一:
go get -u github.com/go-delve/delve/cmd/dlv
方式二

$ git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve
$ cd $GOPATH/src/github.com/go-delve/delve
$ make install

注意: 若果你go版本为1.5需要设置GO15VENDOREXPERIMENT=1

OSX

$ go get -u github.com/go-delve/delve/cmd/dlv

执行上述代码前,确保你电脑上有编译工具

2、调试器配置说明

调试器会使用要以下这些配置, 在通常情况下, 你不需要更改或者修改他们中的任何一项, 但是需要看一看。

  • go.gopath:查看GOPATH in VS Code
  • go.inferGopath: 查看GOPATH in VS Code
  • go.delveConfig
    • apiVersion :启动 headless delve 服务, 需要指定的 delve api 版本, 默认为 2。
    • dlvLoadConfig:当 apiVersion 为 1 时不适用。配置会传递给 delve, 控制 delve 的各种功能,这些功能会影响调试窗格中显示的变量。
      • maxStringLen: 从字符串读取的最大字节数。
      • maxArrayValues: 从数组,切片或 map 中读取的最大元素数。
      • maxStructFields: 从结构读取的最大字段数,-1将读取所有字段。
      • maxVariableRecurse: 嵌套类型读取的最大层级。

虽然大多数情况下你不需要调整配置, 但在以下情况需要调整 delve 的配置

  • 在调试视图中检查变量时,可能需要更改字符串和数组的长度, 默认上限更改为 64。
  • 在调试视图中检查嵌套变量时,请按照实际情况进行配置。

3、设置launch.json配置文件

当 delve 安装后, 运行命令Debug: Open launch.json, 如果没有 launch.json 文件, 则会使用默认配置创建一个文件,此文件用于调试当前程序。

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "env": {},
            "args": []
        }
    ]
}

以下是launch.json中的一些属性说明:

属性 说明
name 定义配置名字
type 指定语言,这里我们填go即可
request launch ,attach, 当需要对一个已经运行的的程序 debug 时才使用 attach,其他时候使用launch
mode 对于 launchauto, debug, remote, test, exec, 对于 attach只有local,remote
program 指定包, 文件或者是二进制的绝对路径
env 调试程序时需要注入的环境变量, 例如:{ "ENVNAME": "ENVVALUE" }
envFile 绝对路径,env的值会覆盖envFile的值
args 需要传给调试程序的命令行参数
showLog 布尔值,是否在调试控制台打印日志, 一般为true
logOutput 日志输出目标, 使用逗号分隔达到使用多个组件输出日志的目的 (debugger, gdbwire, lldbout, debuglineerr, rpc), 当 showLogtrue 有效
buildFlags 构建程序时需要传递给 Go 编译器的 Flags
remotePath 如果moderemote时, 需要指定调试文件所在服务器的绝对路径
processId 进程 id
host 目标服务器地址
port 目标端口

(1)在调试过程中使用 VS Code 变量

  • ${workspaceFolder} 在工作区的的根目录调试程序
  • ${file} 调试当前文件
  • ${fileDirname} 调试当前文件所属的程序包

(2)使用 build tags

如果在构建时需要构建标签, (比如:go build -tags=whatever_tag ), 则需要使用标签buildFlags 并添加内容: "-tags=whatever_tag" ,如果你需要使用多个标签时, 则需要使用单引号引起来,像这样:"-tags='first_tag second_tag third_tag'"

4、常用的launch.json 配置示例

在编辑launch.json时, 你可以将下面这些代码片段用于调试配置。

(1)调试当前文件的配置样本

{
    "name": "Launch file",
    "type": "go",
    "request": "launch",
    "mode": "auto",
    "program": "${file}"
}

(2)调试单个测试用例配置样本

{
    "name": "Launch test function",
    "type": "go",
    "request": "launch",
    "mode": "test",
    "program": "${workspaceFolder}",
    "args": [
        "-test.run",
        "MyTestFunction"
    ]
}

(3)调试包内所有测试用例配置样本

{
    "name": "Launch test package",
    "type": "go",
    "request": "launch",
    "mode": "test",
    "program": "${workspaceFolder}"
}

(4)调试预构建二进制配置样本

{
    "name": "Launch executable",
    "type": "go",
    "request": "launch",
    "mode": "exec",
    "program": "absolute-path-to-the-executable"
}

(5)调试本地已运行进程配置样本

{
    "name": "Attach to local process",
    "type": "go",
    "request": "attach",
    "mode": "local",
    "processId": 0
}

5、远程调试

要使用 VS Code 进行远程调试, 那么需要在远程服务器上运行 headless delve 服务。下面这个示例假定了 你要调试的程序与你在同一目录下, 如果没有, 请参考 dlv debug 命令上的用法文档

# 在远程服务器上启动 delve 服务
$ dlv debug --headless --listen=:2345 --log --api-version=2

如果需要传递参数到程序, 必须通过Delve 服务传递,例如:

$ dlv debug --headless --listen=:2345 --log -- -myArg=123

然后在 VS Code 中创建一个远程调试的launch.json

{
    "name": "Launch remote", 
    "type": "go",
    "request": "launch",
    "mode": "remote",
    "remotePath": "absolute-path-to-the-file-being-debugged-on-the-remote-machine",
    "host": "127.0.0.1", # 目标服务器地址
    "port": 2345, # 目标端口
    "program": "absolute-path-to-the-file-on-the-local-machine",
    "env": {}
}
  • remotePath 应该指向目标服务器中调试文件的绝对路径 (在源代码中)
  • program 指向本地计算机上文件的绝对路径,此路径与 remotePath 对应。

注意: 当选择了这个新的Launch remote配置启动调试器时,VS Code 会将调试命令发送到 目标服务器的 dlv, 而不是针对应用程序启动它自己的 dlv 实例。

在 Docker 中调试参考:https://github.com/lukehoban/webapp-go/tree/debugging

6、一步一步调试

img

例子

我们将使用两个示例来调试我们的Go代码。

  • 一个生成JSON的简单go程序。
  • 我们将编写一个函数,编写测试并查看如何在VS Code中调试测试

示例1:复仇者 (Example 1: Avengers)

这是第一个示例的源代码。 创建一个文件main.go

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

// Avenger represents a single hero
type Avenger struct {
    RealName string `json:"real_name"`
    HeroName string `json:"hero_name"`
    Planet   string `json:"planet"`
    Alive    bool   `json:"alive"`
}

func (a *Avenger) isAlive() {
    a.Alive = true
}

func main() {
    avengers := []Avenger{
        {
            RealName: "Dr. Bruce Banner",
            HeroName: "Hulk",
            Planet:   "Midgard",
        },
        {
            RealName: "Tony Stark",
            HeroName: "Iron Man",
            Planet:   "Midgard",
        },
        {
            RealName: "Thor Odinson",
            HeroName: "Thor",
            Planet:   "Midgard",
        },
    }

    avengers[1].isAlive()

    jsonBytes, err := json.Marshal(avengers)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println(string(jsonBytes))
}

在这里,我们只是定义一个struct Avenger ,然后创建一个复仇者数组,将其中一个复仇者的状态更改为还活着,然后将结果转换为JSON,最后将其打印到STDOUT。

您可以使用

go run main.go
// 输出
[{"real_name":"Dr. Bruce Banner","hero_name":"Hulk","planet":"Midgard","alive":false},{"real_name":"Tony Stark","hero_name":"Iron Man","planet":"Midgard","alive":true},{"real_name":"Thor Odinson","hero_name":"Thor","planet":"Midgard","alive":false}]

要开始调试,我们需要创建一个配置。 单击Visual Studio Code左窗格上的“调试”图标。 接下来,单击齿轮图标以创建配置。

![img](vscode-debug-use/SNYhXvw5QpOJquApssPl_Screen Shot 2018-07-30 at 23.09.50.png)

.vscode/launch.json下创建一个配置文件,其内容如上所示。 更改配置程序以指向main.go文件。 在这种情况下,由于只有main.go文件,因此可以将其更改为工作区根目录:

{
  // ...
  "configuration": [
    {
      // ...
      "program": "${workspaceRoot}",
      // ...
    }
  ]
}

接下来,我们需要添加一个断点,因为这就是调试的全部目的。

让我们在第21行func main()上添加一个断点,方法是单击行号左侧,我们将看到一个红点。

![img](vscode-debug-use/L6KELCfTeyGwSV7OC8qg_Screen Shot 2018-07-30 at 23.15.09.png)

接下来,按F5或单击左上角“调试”部分上带有绿色播放按钮的“启动”按钮。 它应该打开调试视图。

![img](vscode-debug-use/hFD6Oe7DQsyW4UEb6wPx_Screen Shot 2018-07-30 at 23.16.52.png)

在“调试工具栏”上的“ Step Over按钮上单击两次。

![img](vscode-debug-use/kXxTp955RTK6AJogAWTa_Screen Shot 2018-07-30 at 23.39.30.png)

一旦调试器移至第40行。

![img](vscode-debug-use/aIx38lKCRcanrbDVxdIg_Screen Shot 2018-07-30 at 23.41.31.png)

左侧的“调试”部分将为我们提供当前断点位置的状态。

![img](vscode-debug-use/P1KDoXbOSsS67fuEj37z_Screen Shot 2018-07-30 at 23.37.12.png)

我们可以在“变量”部分的特定时间查看变量的状态/值。

我们还可以看到调用堆栈,当前运行函数是main函数,以及line 40

您可以继续Stepping Over ,一旦我们越过线,您将看到avengers的价值发生变化。 "Tony Stark" is Alive.

![img](vscode-debug-use/sJT7KlTS4eQiqO94gk0w_Screen Shot 2018-07-30 at 23.45.11.png)

条件断点 (Conditional Breakpoints)

VSCode断点为您提供了一个选项,可以通过给它们一个表达式来编辑断点,大多数情况下,这些时间通常是布尔表达式。

例如,在第40行avengers[1].isAlive() ,我们可以在此处添加一个条件,即仅当我们要计算的表达式为true时才会引发断点。 例如avenger[1].Planet == "Earth"

为此,请在断点上单击鼠标右键,然后选择“编辑断点”。

![img](vscode-debug-use/uocIXzzGSb8HQLxbpzAQ_Screen Shot 2018-07-30 at 23.48.27.png)

如果没有断点,仍然可以右键单击,然后会提示您添加Conditional Breakpoint

![img](vscode-debug-use/3wMg8wvSqSnhSGguK3pv_Screen Shot 2018-07-30 at 23.53.50.png)

选择以上任意一项后,让我们添加条件。 avenger[1].Planet == "Earth"

![img](vscode-debug-use/CiLhwAwiQWiTv1O9MXB5_Screen Shot 2018-07-30 at 23.54.16.png)

现在,如果您使用F5启动调试器,它将不会在断点处停止。 该应用程序将正常运行,我们将在调试控制台中看到结果。

![img](vscode-debug-use/LxU8aMbQNeQwV3msFYaK_Screen Shot 2018-07-30 at 23.57.01.png)

但是,当我们编辑代码以符合我们的期望时。 将托尼·斯塔克的星球改变为Earth

// ...
{
    RealName: "Tony Stark",
    HeroName: "Iron Man",
    Planet:   "Earth",
},
// ...

当我们再次使用F5启动调试器时,现在将打开“调试视图”,并且执行在断点处停止。 我们可以看到JSON没有显示在调试控制台中

![img](vscode-debug-use/dqddqnWYRGqWhCHHpM6z_Screen Shot 2018-07-30 at 23.59.50.png)

调试测试 (Debugging Tests)

让我们向文件中添加一个新函数,以实现简单的加法运算。

func add(a, b int) int{
    return a+b
}

然后,我们在同一目录中创建测试文件main_test.go ,其中包含以下内容。

package main

import "testing"

func Test_add(t *testing.T) {
    a, b, c := 1, 2, 3

    res := add(a, b)

    if res != c {
        t.Fail()
    }
}

该代码仅将两个数字相加,而测试仅调用该函数。

但是,如果您安装了VSCode-Go插件,您将在测试功能的顶部看到其他选项。 run testdebug test

![img](vscode-debug-use/DrcNNILbQrqHKotioGj2_Screen Shot 2018-07-31 at 00.07.35.png)

您可以单击run test以运行测试,并在“输出”窗口中查看结果。

但是,要调试测试,也许是因为我们无法弄清楚,我们需要做的就是像以前一样添加一个断点,然后单击debug test

if res != c ,让我们在第10行添加一个断点,然后单击debug test。

![img](vscode-debug-use/vMqbDfYIRWKEyMMyRz8t_Screen Shot 2018-07-31 at 00.08.08.png)

“调试”视图再次打开,我们可以使用“调试工具”跳过并检查左侧变量部分的状态。

总结

调试是开发软件的关键部分,借助Visual Studio Code之类的工具,可以使我们的生活变得更加轻松。

我们在这里使用了一个简单的示例来解释这些概念,但是可以随时将调试器添加到任何现有项目中,并进行尝试。 您最终将减少用于记录执行期间给定点代码的值/状态的fmt.Println语句。

7、Troubleshooting

如果在调试 Go 代码遇到问题时, 首先应该更新 delve 版本, 确保使用的是最新的 delve, 并且已使用当前的 Go 版本对其进行了编译。为确保最新版本,请执行命令 Go: Install/Update Tools 选择 dlv, 点击OK

(1)启动调试日志

  • 将调试配置中的showLog属性设置为true。在 delve 的调试控制台可以看到调试日志。

  • 将调试配置中的trace属性设置为log。在调试控制台看到日志的同时也会将日志保存在文件中,日志文件会在调试控制台开头打印出来,注意查看。

  • 将调试配置中的

    logOutput

    属性设置为

    rpc

    。您看到与 VS Code 和 delve 之间往返的 RPC 消息相对应的日志。需要将 showLog 设置为 true。

    • logOutput属性与 delve--log-output标志对应,使用逗号分隔可以输出到多个组价列表。

参考资料

  1. 一步一步 debug
  2. Debugging Go code using VS Code
  3. Delve Installation

   转载规则


《使用 VSCode 调试 Golang》 bill 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
vscode插件使用 vscode插件使用
1、注释插件 koro1FileHeader 使用文档 // 目前默认配置setting.json中添加 "fileheader.customMade": { //此为头部注释 "Author
2020-04-26
下一篇 
lotus FullNodeAPI接口分析 lotus FullNodeAPI接口分析
1、FullNodeAPI全节点接口 source 1.1 Lotus JSON-RPC APIJSON-RPC是在JSON中对远程过程调用进行编码的标准化方法。比特币和以太坊等项目已将其用于其API。 Lotus使用通过HTTP或Web
2020-04-26
  目录