详解Golang如何在编译时注入版本信息

 更新时间:2023年06月18日 08:58:07   作者:Shawn27  
这篇文章主要为大家详细介绍了Golang如何在编译时实现注入版本信息,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解一下

问题

一般而言,稍微做得好一点的开源软件,其二进制文件都会带上版本信息,比如Docker,你可以通过以下命令来查看:

$ docker --version
Docker version 20.10.17, build 100c701
$ docker version
...
//输出太长,这里就不展示了

有些Web应用还提供了/version接口,你可以通过接口来获取:

$ curl http://127.0.0.1:8080/version | jq
{
  "Build Time": "Fri, 16 Jun 2023 16:19:23 +0800",
  "Git Commit": "b554659",
  "Go Version": "go1.19",
  "OS/Arch": "darwin/amd64",
  "version": "0.9.2"
}

然而很多公司并没有这方面的强制性规范,多数开发人员也没有这样的意识或习惯,所以大部分项目并没有实现这个功能。如果二进制文件不带上版本信息,你可能要借助其它系统来查询或追溯,这无疑是一件难受的事,对于代码调试和问题定位很不友好。

那么在Golang中,如何实现这个功能呢?

思路

版本信息有很多,比如代码版本号、Git提交号、编译时间、Go版本号等,如何让二进制文件带上这些信息呢?

硬编码在代码里肯定不行。因为Git提交号是将代码提交到代码仓库时才产生,而Go版本号和编译时间只有在编译时才能拿到。

比较合理的做法是在编译时注入。Go编译工具提供了-ldflags选项,通过-X参数可以注入包变量的值,我们只需要在代码中将版本信息定义成包变量,然后在编译时完成注入即可。这个过程可以实现为自动化完成,下面以make工具为例说明。

实现步骤

1. 在代码中定义版本信息的变量

将代码版本号、Git提交号、编译时间定义为包变量:

package config
var (
	Version   string  //代码版本号
	GitCommit string  //Git提交号
	BuildTime string  //编译时间
)

Go版本号等信息可以借助runtime包获取:

runtime.Version()  //Go版本
runtime.GOOS       //操作系统
runtime.GOARCH     //平台架构

2. 在代码中使用这些变量

1)实现--version参数或version子命令

Cobra命令行框架为例,为rootCmd实现--version参数:

rootCmd.Version = config.Version
rootCmd.SetVersionTemplate(fmt.Sprintf(`{{with .Name}}{{printf "%%s version information: " .}}{{end}}
    {{printf "Version:    %%s" .Version}}
    Git Commit: %s
    Build Time: %s
    Go version: %s
    OS/Arch:    %s/%s
`, config.GitCommit, config.BuildTime, runtime.Version(), runtime.GOOS, runtime.GOARCH))

2)实现/version接口

Gin框架为例,将/version路由到如下的Version函数:

func Version(ctx *gin.Context) {
    ctx.Writer.Header().Set("Content-Type", "application/json")
    ctx.Writer.WriteHeader(http.StatusOK)
    json.NewEncoder(ctx.Writer).Encode(map[string]string{
        "version":    config.Version,
        "Git Commit": config.GitCommit,
        "Build Time": config.BuildTime,
        "Go Version": runtime.Version(),
        "OS/Arch":    runtime.GOOS + "/" + runtime.GOARCH,
    })
}

3. 在编译前获取版本信息

在Makefile中,用git命令获取代码版本号、Git提交号,用date命令获取当前时间

VERSION    = $(shell git describe --tags --always)
GIT_COMMIT = $(shell git rev-parse --short HEAD)
BUILD_TIME = $(shell date -R)

4. 在编译时注入版本信息

在Makefile中,通过-ldflags选项为go build命令传入编译参数,实现版本信息的注入

define LDFLAGS
"-X 'github.com/myname/myapp/config.Version=${VERSION}' \
-X 'github.com/myname/myapp/config.GitCommit=${GIT_COMMIT}' \
-X 'github.com/myname/myapp/config.BuildTime=${BUILD_TIME}'"
endef
build:
    go build -ldflags ${LDFLAGS} -o myapp_${VERSION} .

5. 验证效果

编译出二进制,即可验证--version参数;用二进制启动服务进程,即可验证/version接口。

$ make build
...
//编译过程,省略输出
$ myapp --version
myapp version information: 
    Version:    0.9.2
    Git Commit: b554659
    Build Time: Sat, 17 Jun 2023 11:30:44 +0800
    Go version: go1.20.5
    OS/Arch:    darwin/arm64
$ myapp
...
//启动进程,省略输出
$ curl http://127.0.0.1:8080/version | jq
{
  "Build Time": "Sat, 17 Jun 2023 11:30:44 +0800",
  "Git Commit": "b554659",
  "Go Version": "go1.20.5",
  "OS/Arch": "darwin/arm64",
  "version": "0.9.2"
}

总结

二进制文件直接带上版本信息,能为代码调试和问题定位带来很大的方便。本文介绍了通过-ldflags选项实现在编译时注入版本信息的具体做法。

这是一个比较通用的方法,很多开源软件比如 Docker 也是这样做的。

到此这篇关于详解Golang如何在编译时注入版本信息的文章就介绍到这了,更多相关Golang编译注入版本信息内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go使用Gin框架利用阿里云实现短信验证码功能

    go使用Gin框架利用阿里云实现短信验证码功能

    这篇文章主要介绍了go使用Gin框架利用阿里云实现短信验证码,使用json配置文件及配置文件解析,编写路由controller层,本文通过代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-08-08
  • Go语言文件读取的一些总结

    Go语言文件读取的一些总结

    这篇文章主要介绍了Go语言文件读取的一些总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Go语言中Select语句用法实例

    Go语言中Select语句用法实例

    这篇文章主要介绍了Go语言中Select语句用法,实例分析了select语句的原理与使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Go语言通道之无缓冲通道与缓冲通道详解

    Go语言通道之无缓冲通道与缓冲通道详解

    通道是一种特殊的数据结构,可以在协程之间进行传递数据,从而实现协程之间的通信和同步,本文就来和大家讲讲Go语言通道中的无缓冲通道与缓冲通道吧
    2023-06-06
  • Go语言共享内存读写实例分析

    Go语言共享内存读写实例分析

    这篇文章主要介绍了Go语言共享内存读写方法,实例分析了共享内存的原理与读写技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • go值赋值和引用赋值的使用

    go值赋值和引用赋值的使用

    本文将介绍Go语言中的值赋值和引用赋值,并比较它们之间的差异,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-10-10
  • Mango Cache缓存管理库TinyLFU源码解析

    Mango Cache缓存管理库TinyLFU源码解析

    这篇文章主要为大家介绍了Mango Cache缓存管理库TinyLFU源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 浅析Go语言中闭包的定义与使用

    浅析Go语言中闭包的定义与使用

    闭包是编程语言中的一个重要概念,它允许函数不仅仅是独立的代码块,还可以携带数据和状态,本文将深入探讨闭包的定义、用途和注意事项,以及如何正确使用闭包,有需要的可以参考下
    2023-09-09
  • Go字典使用详解

    Go字典使用详解

    今天和大家一起学习Go语言的字典。Go语言的字典又称为map,一种使用广泛的数据结构。它是拥有key/value对元素的「无序集合」,而且在集合中key必须是唯一的
    2022-11-11
  • Golang实现字符串倒序的几种解决方案

    Golang实现字符串倒序的几种解决方案

    给定一个字符串,按单词将该字符串逆序是我们大家在开发中可能会遇到的一个需求,所以下面这篇文章主要给大家介绍了关于Golang如何实现字符串倒序的几种解决方案,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10

最新评论