詳解Golang如何在編譯時注入版本信息
問題
一般而言,稍微做得好一點的開源軟件,其二進(jìn)制文件都會帶上版本信息,比如Docker,你可以通過以下命令來查看:
$ docker --version Docker version 20.10.17, build 100c701 $ docker version ... //輸出太長,這里就不展示了
有些Web應(yīng)用還提供了/version接口,你可以通過接口來獲?。?/p>
$ 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"
}然而很多公司并沒有這方面的強(qiáng)制性規(guī)范,多數(shù)開發(fā)人員也沒有這樣的意識或習(xí)慣,所以大部分項目并沒有實現(xiàn)這個功能。如果二進(jìn)制文件不帶上版本信息,你可能要借助其它系統(tǒng)來查詢或追溯,這無疑是一件難受的事,對于代碼調(diào)試和問題定位很不友好。
那么在Golang中,如何實現(xiàn)這個功能呢?
思路
版本信息有很多,比如代碼版本號、Git提交號、編譯時間、Go版本號等,如何讓二進(jìn)制文件帶上這些信息呢?
硬編碼在代碼里肯定不行。因為Git提交號是將代碼提交到代碼倉庫時才產(chǎn)生,而Go版本號和編譯時間只有在編譯時才能拿到。
比較合理的做法是在編譯時注入。Go編譯工具提供了-ldflags選項,通過-X參數(shù)可以注入包變量的值,我們只需要在代碼中將版本信息定義成包變量,然后在編譯時完成注入即可。這個過程可以實現(xiàn)為自動化完成,下面以make工具為例說明。
實現(xiàn)步驟
1. 在代碼中定義版本信息的變量
將代碼版本號、Git提交號、編譯時間定義為包變量:
package config var ( Version string //代碼版本號 GitCommit string //Git提交號 BuildTime string //編譯時間 )
Go版本號等信息可以借助runtime包獲?。?/p>
runtime.Version() //Go版本 runtime.GOOS //操作系統(tǒng) runtime.GOARCH //平臺架構(gòu)
2. 在代碼中使用這些變量
1)實現(xiàn)--version參數(shù)或version子命令
以Cobra命令行框架為例,為rootCmd實現(xiàn)--version參數(shù):
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)實現(xiàn)/version接口
以Gin框架為例,將/version路由到如下的Version函數(shù):
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命令獲取當(dāng)前時間
VERSION = $(shell git describe --tags --always) GIT_COMMIT = $(shell git rev-parse --short HEAD) BUILD_TIME = $(shell date -R)
4. 在編譯時注入版本信息
在Makefile中,通過-ldflags選項為go build命令傳入編譯參數(shù),實現(xiàn)版本信息的注入
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. 驗證效果
編譯出二進(jìn)制,即可驗證--version參數(shù);用二進(jìn)制啟動服務(wù)進(jìn)程,即可驗證/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
...
//啟動進(jìn)程,省略輸出
$ 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"
}總結(jié)
二進(jìn)制文件直接帶上版本信息,能為代碼調(diào)試和問題定位帶來很大的方便。本文介紹了通過-ldflags選項實現(xiàn)在編譯時注入版本信息的具體做法。
這是一個比較通用的方法,很多開源軟件比如 Docker 也是這樣做的。
到此這篇關(guān)于詳解Golang如何在編譯時注入版本信息的文章就介紹到這了,更多相關(guān)Golang編譯注入版本信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Golang實現(xiàn)WebSocket心跳機(jī)制
WebSocket是一種在客戶端和服務(wù)器之間實現(xiàn)全雙工通信的協(xié)議,它允許實時地傳輸數(shù)據(jù),并且比傳統(tǒng)的HTTP請求更加高效,在使用Golang構(gòu)建WebSocket應(yīng)用程序時,一個重要的考慮因素是如何實現(xiàn)心跳機(jī)制,所以本文將探討如何使用Golang實現(xiàn)WebSocket心跳2023-11-11
idea搭建go環(huán)境實現(xiàn)go語言開發(fā)
這篇文章主要給大家介紹了關(guān)于idea搭建go環(huán)境實現(xiàn)go語言開發(fā)的相關(guān)資料,文中通過圖文介紹以及代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用go具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01
基于golang的簡單分布式延時隊列服務(wù)的實現(xiàn)
這篇文章主要介紹了基于golang的簡單分布式延時隊列服務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02

