goland调试go代码_debug运行

goland调试go代码_debug运行如何使用dlv结合Goland进行程序debug调试相信很多Golang的初级玩家不会进行程序的Debug定位问题单纯的靠脑子,或者效率很低的不断的添加日志打印,别问我为什么知道的因为我就是这样的,最好最快捷的问题定位方式一定是使用Debug打断点调试,这时就引出了本文的主角dlv。实际上,delve才是全称,dlv只是启动命令,如果VScode,Goland,默认使用的调试器就是基于delve的。安装dlv参考官方的安装方法,把dlv命令安装在go.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

如何使用 dlv 结合 Goland 进行程序 debug 调试

相信很多 Golang 的初级玩家不会进行程序的 Debug 定位问题单纯的靠脑子,或者效率很低的不断的添加日志打印,别问我为什么知道的因为我就是这样的,最好最快捷的问题定位方式一定是使用 Debug 打断点调试,这时就引出了本文的主角dlv。

实际上,delve 才是全称,dlv 只是启动命令,如果 VScode,Goland,默认使用的调试器就是基于 delve 的。

安装 dlv

参考官方的安装方法,把 dlv 命令安装在 gopath 的 bin 目录下(需要你把go的bin目录添加到$PATH)

GO

1
2
3

Jetbrains全家桶1年46,售后保障稳定

git clone https://github.com/go-delve/delvecd delvego install github.com/go-delve/delve/cmd/dlv

成功安装执行

APPLESCRIPT

1
dlv version

得到:

BASH

1
2
3
Delve Debugger
Version: 1.7.1
Build: $Id: 3bde2354aafb5a4043fd59838842c4cd4a8b6f0b $

进入调试模式有以下几种办法(重要

  1. dlv attach pid:对正在运行的进程直接进行调试(pid 为进程id);
  2. dlv debug:编译源文件并开始调试,这里应和 main 函数位于同一目录,或者指定完整的 main 函数路径
  3. dlv exec filename:从二进制文件启动调试

这三种模式是调试的重要基础,接下来会通过实际案例来讲解如何使用这三种模式。

直接编译源文件进行本地调试:

使用 dlv debug 命令直接进行源码的编译,以及断点设置,并使用命令查看断点处的参数等信息

比如使用 break 或 b 设置一个断点,使用bp 查看目前打的断点,

dlv 常用的命令总结如下:

命令 含义
b 设置断点
bp 打印正活动的断点信息
clear 删除断点
clearall 删除所有断点
c 运行直到断点处或程序终止
n 下一步,不会进入函数
s 下一步,会进入函数
so 跳出当前函数
args 查看函数参数
locals 查看所有局部变量
list 打印当前源代码
on 运行到某断点然后执行相应的命令,比如 on 2 list
bt 打印当前调用栈
exit 退出
goroutines (grs) 列出所有的 goroutines
goroutine (gr) 查看当前的 goroutine

这样做是十分麻烦的,这个介绍只是让我们理解dlv是如何工作的。一般我们都会结合 idea 进行界面化的调试,那么接下来我们以goland为例子进行 debug 调试。

做一个简单的 demo 代码可见这里:

GO

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
const timeoutOpenAPIQuit     = 2 * time.Minute

func main(){
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	g, ctx := errgroup.WithContext(ctx)

	e := gin.Default()

	e.GET("/api/v1/hello",Hello)

	g.Go(func() (err error) {
		defer func() {
			err = WrapPanicErr(err, recover())
		}()

		err = ServerRun(ctx, ":8080", e, timeoutOpenAPIQuit)
		if err != nil {
			err = fmt.Errorf("failed to run open api serv: %w", err)
		}
		return
	})

	if err := g.Wait(); err != nil {
		logrus.Error(err)
	}

	logrus.Info("all services are down")

}

func Hello(c *gin.Context){
	name := c.Query("name")
	str := fmt.Sprintf("hello %s ! \n",name)
	fmt.Println(str)

	c.String(http.StatusOK,str)

}

很简单的监听 8080 端口,给出一个 hello 的请求回应方法。

使用gland 进行debug模式编译:

goland调试go代码_debug运行

出现如下窗口:

goland调试go代码_debug运行

在你需要的地方打上断点:

goland调试go代码_debug运行

尝试请求后跳到你的断点处,即可进行操作调试:

goland调试go代码_debug运行

使用 Goland 配合 dlv 调试二进制方式进行debug

对你的程序进行编译,-gcflags 为必须添加的。

BASH

1
go build -o hello -gcflags "all=-N -l" 

使用dlv启动你的程序

BASH

1
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./hello

配置 Goland 进行调试程序连接 Run -> Debug -> 0 EditConfiguration

goland调试go代码_debug运行

添加一个 Go Remode : 命名随意,Host 和 Port 配置你使用dlv 启动的程序监听

goland调试go代码_debug运行

点击 Debug 出现以下界面表示连接成功:

goland调试go代码_debug运行

尝试去访问直接回跑到断点处:

goland调试go代码_debug运行

使用dlv 进行 Docker 镜像远程调试

相信很多小伙伴都遇到过本地环境的数据不够丰富,在本地自测完全没有问题,一到测试环境居然凉了,这时候使用测试环境的debug就很重要了,我们可以以使用 dlv 的二进制文件启动调试的方式进行远程的镜像调试。

方式一:使用 dlv 入侵 docker 中正在执行的进程 ID

准备:

这种方式的好处是不用破坏部署真实环境使用的 dockerfile 调试完成结束掉dlv 不影响线上的部署环境的正常运行,不好的地方就是比较麻烦,

Dockerfile:

DOCKERFILE

1
2
3
4
5
6
FROM alpine

COPY hello /usr/local/hello
WORKDIR /usr/local/

CMD ["./hello"]

这个文件是 docker 镜像启动后的执行文件,即使用 dlv 侵入docker 中运行的进程id,该文件放入deploy文件夹下。

startdlv.sh:

BASH

1
2
3
#!/bin/bash

dlv debug --headless --listen=:2345 --api-version=2 --accept-multiclient attach $PID

这个文件用来在服务器上执行,把docker 镜像压缩包加载出来

install.sh:

BASH

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

VERSION=%%VERSION%%

echo VERSION
docker load < dlv_${VERSION}.tar
echo "加载完毕。。。"

docker run -d -p 8080:8080 --security-opt=seccomp:unconfined dlv:${VERSION}
echo "成功跑起。。。"

Makefile:

MAKEFILE

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
DlVVERSION=$(v)

IMAGENAME_CERTMANAGER=dlv:$(DlVVERSION)

_buildEnv=CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64

# 构建程序的二进制文件 注意-gcflags 一定要添加
build:
	@$(_buildEnv) go build \
			-o hello -gcflags "all=-N -l"
	@echo "hello build done"

# 构建 docker 镜像
docker:build
	@docker build -t dlv:$(DlVVERSION) ./
	@echo " docker build done"

# 压缩 docker 镜像,注入docker压缩包, install.sh 到 deploy 文件夹,deploy文件夹下还要有上文的 startdlv.sh 文件
save:docker
	@sed "s/%%VERSION%%/$(DlVVERSION)/g" install.sh > deploy/install.sh
	@chmod +x deploy/install.sh
	@docker save $(IMAGENAME_CERTMANAGER) > deploy/dlv_$(DlVVERSION).tar
	@scp -r deploy root@你的服务器IP:~/
	@echo "save done"

看下几个文件的位置,有助于理解:

goland调试go代码_debug运行

搞起

执行 v=1.0.0 make save :

goland调试go代码_debug运行

可以看到install.sh , dlv_1.0.0.tar , startdlv.sh 都远程拷贝到了我的服务器(忽略那个dlv_1.0.1.tar):

goland调试go代码_debug运行

首先执行install.sh:

goland调试go代码_debug运行

此时我们的容器已经成功跑起来了,接下来获取容器中执行程序hello的PID:

goland调试go代码_debug运行

可以看到是 19184,改掉我们的 startdlv.sh 中 $PID 为19184,执行该文件:

goland调试go代码_debug运行

可以看到dlv 已经入侵到了此进程并监听在2345端口,按照上文的goland添加Go Remode IP 为我的服务器IP,端口同样为2345,连接该dlv 程序(我命名为AliyunHello) :

goland调试go代码_debug运行

此时就完成了远程debug的部署工作,我们访问一下我的服务器上的hello程序:

goland调试go代码_debug运行

程序hold住并且进入了断点调试状态,很棒成功了!这样就可以愉快的调试了。

方式二:使用 dlv 直接在容器中执行 hello 程序

准备:

这种方式的好处是方便,直接跑起来 docker 即可进行调试,但它一直处在调试状态,是不可与你的测试环境并行的,你需要新建一套环境,而且 docker 中是需要go环境的,导致镜像变得很大。(说在前面,这种方法我没成功。。。找到问题我会更新的)

Dockerfile:

DOCKERFILE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM golang:1.17.1-alpine3.14 as build

RUN set -eux && \
  apk update && \
  apk add --no-cache git curl && \
  go get -u github.com/go-delve/delve/cmd/dlv && \
  go build -o /usr/local/bin/dlv github.com/go-delve/delve/cmd/dlv

COPY hello /usr/local/hello
WORKDIR /usr/local/


CMD ["dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./hello"]

这个文件用来在服务器上执行,把docker 镜像压缩包加载出来

install.sh:

BASH

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

VERSION=%%VERSION%%

echo VERSION
docker load < dlv_${VERSION}.tar
echo "加载完毕。。。"

docker run -d -p 8080:8080 -p 2345:2345 --security-opt=seccomp:unconfined dlv:${VERSION}
echo "成功跑起。。。"

Makefile:

MAKEFILE

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
DlVVERSION=$(v)

IMAGENAME_CERTMANAGER=dlv:$(DlVVERSION)

_buildEnv=CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64

# 构建程序的二进制文件 注意-gcflags 一定要添加
build:
	@$(_buildEnv) go build \
			-o hello -gcflags "all=-N -l"
	@echo "hello build done"

# 构建 docker 镜像
docker:build
	@docker build -t dlv:$(DlVVERSION) ./
	@echo " docker build done"

# 压缩 docker 镜像,注入docker压缩包, install.sh 到 deploy 文件夹,deploy文件夹下还要有上文的 startdlv.sh 文件
save:docker
	@sed "s/%%VERSION%%/$(DlVVERSION)/g" install.sh > deploy/install.sh
	@chmod +x deploy/install.sh
	@docker save $(IMAGENAME_CERTMANAGER) > deploy/dlv_$(DlVVERSION).tar
	@scp -r deploy root@你的服务器IP:~/
	@echo "save done"

这个方式就不需要找到进程ID 然后再进行dlv 入侵了,直接跑起 docker 就好,注意把2345端口映射出来。这种方式我失败了,每次在docker run 的时候都会报 no such file :

goland调试go代码_debug运行

不知道为什么,可能是环境问题,我进入容器内部,执行dlv –listen=:2345 –headless=true –api-version=2 –accept-multiclient exec ./hello 就可以,但在dockerfile 里执行这个命令就会报no such file , 没有找到问题的原因,之后找到原因会更新的,推荐使用第一种方式吧,我觉得比较好,虽然要获取进程ID。

文章作者: Mark’s Blog

文章链接: 如何使用 dlv 结合 Goland 进行程序 debug 调试 | Mark’s Blog

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Mark’s Blog

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231296.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • c语言里void什么作用,C语言中void是什么意思?

    c语言里void什么作用,C语言中void是什么意思?C语言中void是什么意思?C语言中“void”表示为无类型,相应的“void*”为无类型指针,常用在程序编写中对定义函数的参数类型、返回值、函数中指针类型进行声明,其作用是对函数返回和参数的进行限定。C语言关键字auto:声明自动变量break:跳出当前循环case:开关语句分支char:声明字符型变量或函数返回值类型const:声明只读变量continue:结束当前循环,开始下一轮循环…

    2022年5月12日
    53
  • 串口助手(简洁版)上位机软件零基础教程( C# + visual studio2017 )(二)

    串口助手(简洁版)上位机软件零基础教程( C# + visual studio2017 )(二)在上篇博客中,我们完成了串口助手(简洁版)可视化窗体的设计,并且单击启动后可以运行。但是光有外壳,没有灵魂。所以接下来我们将继续一步一步来编写上位机软件的程序部分。首先,我谈一下自己所理解的C#上位机软件程序编写的中心思想。以串口助手(简洁版)为例,所有程序都是以“事件”为核心来进行的,对应的“事件”发生了,那软件就去执行我们自己编写的对应…

    2022年5月31日
    78
  • Java和C++的区别

    Java和C++的区别Java和C++的区别:1.Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码。对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了。2.C++是编译型语言,所谓编译型语言,就是源码一次编译,直接在编译的过程中链接了,形成了机器码。3.C++比Java执行速度快,但是Java可以利用JVM跨平台。4….

    2022年7月7日
    24
  • 机房收费系统——上下机「建议收藏」

    机房收费系统——上下机「建议收藏」机房收费系统——上下机

    2022年4月24日
    40
  • obs录制黑屏怎么解决_obs窗口捕获黑屏

    obs录制黑屏怎么解决_obs窗口捕获黑屏00.目录文章目录00.目录01.问题描述02.问题分析03.问题解决04.成功测试01.问题描述打开OBS后,新建场景、新建显示器捕获后,黑屏没有显示,即使点击开始录制,然后结束录制后,录制的视频仍然是黑屏。02.问题分析安装包是从官网下载的,安装过程没有报错,启动过程也没有报错,但是却捕捉不到显示器中的图像。首先考虑的是软件兼容性的问题,但是在我将兼容性设置成”W…

    2022年4月19日
    108
  • Ubuntu18.04安装教程

    Ubuntu18.04安装教程Ubuntu18.04.1安装一、准备工作1.下载Ubuntu18.04.1LTS2.制作U盘启动盘3.准备Ubuntu18.04.1的硬盘空间二、安装Ubuntu18.04.1三、安装后的一些工作1.安装输入法2.更换软件源四、双系统如何卸载Ubuntu18.04.1新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列…

    2022年5月4日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号