golang之增加版本信息功能

在实际开发中,当开发完一个 apiserver 特性后,会编译 apiserver 二进制文件并发布到生产环境,很多时候为了定位问题和出于安全目的(不能发错版本),我们需要知道当前 apiserver 的版本,以及一些编译时候的信息,如编译时 Go 的版本、Git 目录是否 clean,以及基于哪个 git commmit 来编译的。在一个编译好的可执行程序中,我们通常可以用类似 ./app_name -v 的方式来获取版本信息。

我们可以将这些信息写在配置文件中,程序运行时从配置文件中取得这些信息进行显示。但是在部署程序时,除了二进制文件还需要额外的配置文件,不是很方便。或者将这些信息写入代码中,这样不需要额外的配置,但要在每次编译时修改代码文件,也比较麻烦。Go 官方提供了一种更好的方式:通过 -ldflags -X importpath.name=value(详见 -ldflags -X importpath.name=value)来给程序自动添加版本信息。

 

1.增加参数-v

package main

import (
    "encoding/json"
    "fmt"
    "os"
    ...
    v "apiserver/pkg/version"
    ...
)

var (
    version = pflag.BoolP("version", "v", false, "show version info.")
)

func main() {
    pflag.Parse()
    if *version {
        v := v.Get()
        marshalled, err := json.MarshalIndent(&v, "", "  ")
        if err != nil {
            fmt.Printf("%v\n", err)
            os.Exit(1)
        }

        fmt.Println(string(marshalled))
        return
    }
    ...
}

pkg/version包中的实现:

base.go

package version

// 变量通过-ldflags -X importpath.name=value在编译时传入程序中
var (
    gitTag       = "" //
    gitBranch    = ""
    gitCommit    = "$Format:%H$"
    gitTreeState = "not a git tree"
    buildDate    = "1970-01-01T00:00:00Z"
)

version.go

package version

import (
    "fmt"
    "runtime"
)

type Info struct {
    GitTag       string `json:"gitTag"`
    GitBranch    string `json:"gitBranch"`
    GitCommit    string `json:"gitCommit"`
    GitTreeState string `json:"gitTreeState"`
    BuildDate    string `json:"buildDate"`
    GoVersion    string `json:"goVersion"`
    Compiler     string `json:"compiler"`
    Platform     string `json:"platform"`
}

func (info Info) String() string {
    return info.GitTag
}

func Get() Info {
    return Info{
        GitTag:       gitTag,
        GitBranch:    gitBranch,
        GitCommit:    gitCommit,
        GitTreeState: gitTreeState,
        BuildDate:    buildDate,
        GoVersion:    runtime.Version(),
        Compiler:     runtime.Compiler,
        Platform:     fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
    }
}

其中的gitTag, gitBranch,gitComit,gitTreeState,buildDate信息都是在build的时候, 使用-ldflags -X key=value的方式指定参数

Makefile文件中:

.PHONY: all build windows mac run tidy check cert test cover lint docker clean help

BIN_FILE=golang-demo
MAIN_FILE=./cmd/app/main.go


SHELL := /bin/bash
BASEDIR = $(shell pwd)

# build with verison infos
versionDir = "golang-demo/pkg/version"
## 获取仓库tag
gitTag = $(shell if [ "`git describe --tags --abbrev=0 2>/dev/null`" != "" ];then git describe --tags --abbrev=0; else git log --pretty=format:'%h' -n 1; fi)
buildDate = $(shell TZ=Asia/Shanghai date +%FT%T%z)
gitCommit = $(shell git log --pretty=format:'%H' -n 1)
gitTreeState = $(shell if git status|grep -q 'clean';then echo clean; else echo dirty; fi)
gitBranch = $(shell git rev-parse --abbrev-ref HEAD)

ldflags="-w -X ${versionDir}.gitTag=${gitTag} -X ${versionDir}.buildDate=${buildDate} -X ${versionDir}.gitBranch=${gitBranch} -X ${versionDir}.gitCommit=${gitCommit} -X ${versionDir}.gitTreeState=${gitTreeState}"

# 默认执行
all: build

# 打包成二进制文件
build: tidy check
    @CGO_ENABLED=0 GOOS=linux GOARCH=amd64  go build -v -ldflags $(ldflags) -o $(BIN_FILE)_linux $(MAIN_FILE)

windows: tidy check
    @CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -v -ldflags "-w -s" -o $(BIN_FILE)_windows.exe $(MAIN_FILE)

mac: tidy check
    @CGO_ENABLED=0 GOOS=darwin GOARCH=amd64  go build -v -ldflags "-w -s" -o $(BIN_FILE)_darwin $(MAIN_FILE)

# 启动服务
run:
    @go run $(MAIN_FILE) -c ./config/config.yaml


tidy:
    @go mod tidy


# 代码验证
check:
    @gofmt -s -w ./
    @go vet $(MAIN_FILE)

cert:
    @openssl req -new -nodes -x509 -out config/server.crt -keyout config/server.key -days 3650 -subj "/C=DE/ST=NRW/L=Earth/O=Random Company/OU=IT/CN=127.0.0.1/emailAddress=xxxxx@qq.com"



# 单元测试
test:
    @go test ./...

# 覆盖测试
cover:
    @go test -coverprofile xx.out
    @go tool cover -html=xx.out

lint:
    @golangci-lint run --enable-all


docker:
    @docker build -t golang-demo:latest .

clean:
    @go clean -x
    rm -f "xx.out"


help:
    @echo "make - 格式化go代码 并编译生成二进制文件"
    @echo "make test - 执行测试case"
    @echo "make check - 代码检查"
    @echo "make cover - 检测测试覆盖率"
    @echo "make run - 启动服务"
    @echo "make lint - 执行代码检查"
    @echo "make docker - 生成Docker镜像"
    @echo "make clean - 清理中间目标文件"
    @echo "make build - 编译成二进制文件(默认:Linux)"
    @echo "make windows - 编译成二进制文件(Windows)"
    @echo "make mac - 编译成二进制文件(Mac)"

# include ./TestMakefile 包含其他Makefile

-w:  去除调试信息, 无法使用gdb调试, 但是二进制文件更小

 

执行./golang-demo -v

{
        "gitTag": "d62a870",
        "gitBranch": "master",
        "gitCommit": "d62a87056066b2f8ecf6caf64b3bd1d80d60a5e1",
        "gitTreeState": "dirty",
        "buildDate": "2023-08-24T17:10:45+0800",
        "goVersion": "go1.20.7",
        "compiler": "gc",
        "platform": "linux/amd64"
}

 

posted @ 2023-08-24 19:29  X-Wolf  阅读(163)  评论(0编辑  收藏  举报