查看原文
其他

如何使用 dlv 调试 Golang 程序?

Go开发大全 2021-07-20

(给Go开发大全加星标)

来源:Curpointer

https://zhuanlan.zhihu.com/p/126183467

【导读】golang调试工具dlv在开发工作中非常实用,怎么装、怎么用?本文带你快速上手dlv调试工具。

今早思考,在go语言的学习过程中,我们常用调试PHP的方法对某个变量进行print或者log输出,虽然这样的操作可以解决大部分的程序问题。但是,如果面对goroutine这样的调试输出,又该如何进行呢?

OK,Go给我们提供了一个非常好用的调试工具dlv(类似于gdb)。

1、delve(dlv)安装方法

dlv的具体安装方法参考:https://github.com/go-delve/delve

由于我的环境是Linux Centos环境,所以选择Linux安全,这里有两种方法,选择哪种方法都可以。

安装成功后,运行dlv命令,显示如下图所示:

2、Debug 第一个golang程序

Description:程序是从一个config.yaml文件中读取配置信息输出。

其中,config.yaml是我们的配置文件:

TimeStamp: "2018-07-16 10:23:19"
Author: "WZP"
PassWd: "Hello"
Information:
  Name: "Harry"
  Age: "37"
  Alise:
    - "Lion"
    - "NK"
    - "KaQS"
  Image: "/path/header.rpg"
  Public: false

Favorite:
  Sport:
    - "swimming"
    - "football"
  Music:
    - "zui xuan min zu feng"
  LuckyNumber: 99

主程序main.go文件:

package main

import (
        "fmt"
        "log"

        "github.com/spf13/viper"
)

type config struct {
        v *viper.Viper
}

func LoadConfigFromYaml(c *config) error {
        c.v = viper.New()
        c.v.SetConfigFile("./config.yaml")

        if err := c.v.ReadInConfig(); err != nil {
                return err
        }
        age := c.v.Get("Information.Age")
        name := c.v.Get("Information.Name")
        log.Printf("age:%s, name:%s\n", age, name)

        m := c.v.Sub("information")
        log.Printf("keys:%s, image:%s", m.AllKeys(), m.Get("image"))
        return nil
}

func main() {
        cfg := config{v: viper.New()}
        if err := LoadConfigFromYaml(&cfg); err != nil {
                fmt.Println("Failed read config")
        }
}

3、启动dlv debug main.go

dlv debug main.go
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x97be08 for main.main() ./main.go:30
(dlv) continue
> main.main() ./main.go:30 (hits goroutine(1):1 total:1) (PC: 0x97be08)
    25:         m := c.v.Sub("information")
    26:         log.Printf("keys:%s, image:%s", m.AllKeys(), m.Get("image"))
    27:         return nil
    28: }
    29:
=>  30: func main() {
    31:         cfg := config{v: viper.New()}
    32:         if err := LoadConfigFromYaml(&cfg); err != nil {
    33:                 fmt.Println("Failed read config")
    34:         }
    35: }
(dlv) break main.LoadConfigFromYaml
Breakpoint 2 set at 0x97b9eb for main.LoadConfigFromYaml() ./main.go:14
(dlv) c
> main.LoadConfigFromYaml() ./main.go:14 (hits goroutine(1):1 total:1) (PC: 0x97b9eb)
     9:
    10: type config struct {
    11:         v *viper.Viper
    12: }
    13:
=>  14: func LoadConfigFromYaml(c *config) error {
    15:         c.v = viper.New()
    16:         c.v.SetConfigFile("./config.yaml")
    17:
    18:         if err := c.v.ReadInConfig(); err != nil {
    19:                 return err
(dlv) next
> main.LoadConfigFromYaml() ./main.go:15 (PC: 0x97ba0d)
    10: type config struct {
    11:         v *viper.Viper
    12: }
    13:
    14: func LoadConfigFromYaml(c *config) error {
=>  15:         c.v = viper.New()
    16:         c.v.SetConfigFile("./config.yaml")
    17:
    18:         if err := c.v.ReadInConfig(); err != nil {
    19:                 return err
    20:         }
(dlv) break 21
Breakpoint 3 set at 0x97bac4 for main.LoadConfigFromYaml() ./main.go:21
(dlv) c
> main.LoadConfigFromYaml() ./main.go:21 (hits goroutine(1):1 total:1) (PC: 0x97bac4)
    16:         c.v.SetConfigFile("./config.yaml")
    17:
    18:         if err := c.v.ReadInConfig(); err != nil {
    19:                 return err
    20:         }
=>  21:         age := c.v.Get("Information.Age")
    22:         name := c.v.Get("Information.Name")
    23:         log.Printf("age:%s, name:%s\n", age, name)
    24:
    25:         m := c.v.Sub("information")
    26:         log.Printf("keys:%s, image:%s", m.AllKeys(), m.Get("image"))
(dlv) next
> main.LoadConfigFromYaml() ./main.go:22 (PC: 0x97bb0e)
    17:
    18:         if err := c.v.ReadInConfig(); err != nil {
    19:                 return err
    20:         }
    21:         age := c.v.Get("Information.Age")
=>  22:         name := c.v.Get("Information.Name")
    23:         log.Printf("age:%s, name:%s\n", age, name)
    24:
    25:         m := c.v.Sub("information")
    26:         log.Printf("keys:%s, image:%s", m.AllKeys(), m.Get("image"))
    27:         return nil
(dlv) p age
interface {}(string) "37"
(dlv) n
> main.LoadConfigFromYaml() ./main.go:23 (PC: 0x97bb55)
    18:         if err := c.v.ReadInConfig(); err != nil {
    19:                 return err
    20:         }
    21:         age := c.v.Get("Information.Age")
    22:         name := c.v.Get("Information.Name")
=>  23:         log.Printf("age:%s, name:%s\n", age, name)
    24:
    25:         m := c.v.Sub("information")
    26:         log.Printf("keys:%s, image:%s", m.AllKeys(), m.Get("image"))
    27:         return nil
    28: }
(dlv) locals
age = interface {}(string) "37"
name = interface {}(string) "Harry"
(dlv) c
2020/04/06 14:03:29 age:37, name:Harry
2020/04/06 14:03:29 keys:[alise image public name age], image:/path/header.rpg
Process 5775 has exited with status 0

简单介绍一下,上述使用的命令:

1、dlv debug main.go #debug一个main.go程序
2、break(b)main.main #在main包里的main函数入口打断点
3、continue(c) #继续运行,直到断点处停止
4、next(n) #单步运行
5、locals #打印local variables
6、print(p) #打印一个变量或者表达式
7、restart(r) #Restart Process

以上是常用的调试命令,还有一些command,可以执行dlv help查看具体用法,本篇就到这里,Done!


 - EOF -

推荐阅读(点击标题可打开)

1、Golang中的nil,没有人比我更懂nil!

2、Prometheus k8s Operator监控系统

3、Golang 日志框架 Zap 入坑指南


Go 开发大全

参与维护一个非常全面的Go开源技术资源库。日常分享 Go, 云原生、k8s、Docker和微服务方面的技术文章和行业动态。

关注后获取

回复 Go 获取6万star的Go资源库



分享、点赞和在看

支持我们分享更多好文章,谢谢!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存