自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go編譯時寫入數(shù)據(jù)的原理

開發(fā) 后端
在很多公司甚至開源項(xiàng)目都會采用該方式,在代碼中顯式地添加版本等信息。Go是編譯型語言,版本等信息是否可以在編譯時,自動地打包到二進(jìn)制文件中?

[[417666]]

場景

公司線上運(yùn)行的Go服務(wù)存在多個版本

時間:某天凌晨

事情:線上Go服務(wù)突然間 crash

緊急處理:重啟Go服務(wù)

故障排查:查詢?nèi)罩?,找出可能出現(xiàn)的堆棧信息以及追溯源碼

問題:線上同時存在多個版本,如何知道當(dāng)前 crash 的程序?qū)儆谀膫€版本?

添加版本信息的兩種方案

方案1,手動添加版本信息:

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6. // 下面三個變量,每次發(fā)版都要修改 
  7. var version = "v0.0.1" // 程序版本號 
  8. var gitTag = "v0.0.1" // git tag 號 
  9. var dateTime = "2021-08-14 10:00:00" // 編譯生成時間 
  10.  
  11. func main() { 
  12.     debugVerInfo := flag.Bool("ver"false"show app version info"
  13.     flag.Parse() 
  14.  
  15.     if *debugVerInfo { 
  16.         fmt.Println("version is:", version) 
  17.         fmt.Println("dateTime is:", dateTime) 
  18.         fmt.Println("gitTag is:", gitTag) 
  19.         return 
  20.     } 
  21.  
  22.     fmt.Println("do other thing"

由于手動在代碼中添加版本信息,所以在排查時可以查看到對應(yīng)信息。

  1. ➜  code ✗ ./client -ver   
  2. version is: v0.0.1 
  3. dateTime is: 2021-08-14 10:00:00 
  4. gitTag is: v0.0.1 

分析:

在很多公司甚至開源項(xiàng)目都會采用該方式,在代碼中顯式地添加版本等信息。

  1. 假設(shè)不經(jīng)常發(fā)版或者發(fā)版周期比較長,則完全沒問題
  2. 假設(shè)發(fā)版頻繁,很大概率會出現(xiàn)版本信息的遺漏、錯誤
  3. 假設(shè)版本信息忘記更改,則查詢出來的信息就是錯的

針對以上情況,提出一個問題:Go是編譯型語言,版本等信息是否可以在編譯時,自動地打包到二進(jìn)制文件中?

方案2,自動打包版本信息:

  1. package main 
  2.  
  3. import ( 
  4.     "flag" 
  5.     "fmt" 
  6.  
  7. var version = "v0.0.0"// 此處暫時只填寫大的版本號 
  8. var gitTag string 
  9. var dateTime string 
  10.  
  11. func main() { 
  12.     debugVerInfo := flag.Bool("ver"false"show app version info"
  13.     flag.Parse() 
  14.  
  15.     if *debugVerInfo { 
  16.         fmt.Println("version is:", version) 
  17.         fmt.Println("dateTime is:", dateTime) 
  18.         fmt.Println("gitTag is:", gitTag) 
  19.         return 
  20.     } 
  21.  
  22.     fmt.Println("do other thing"

 在編譯時,打包版本等信息到Go的二進(jìn)制文件中:

  1. go build -ldflags \ 
  2.     "-X main.version=v0.0.1 -X main.dateTime=`date +%Y-%m-%d,%H:%M:%S` -X main.gitTag=`git tag`" \ 
  3.   -o client 

build 通過 -ldflags 的 -X 參數(shù)可以在編譯時將值寫入變量

變量格式:包名稱.變量名稱=值

查看版本信息

  1. ➜  code ✗ ./client -ver   
  2. version is: v0.0.1 
  3. dateTime is: 2021-08-14 10:00:00 
  4. gitTag is: v0.0.1 

優(yōu)點(diǎn):

無需代碼中顯式添加版本等信息

避免手動添加版本信息時,遺漏或者錯誤等情況發(fā)生

可使用持續(xù)集成工具自動把版本等信息打包到二進(jìn)制文件中

原理

二進(jìn)制文件在加載到內(nèi)存中之后,整個內(nèi)存空間會被劃分為若干段。除了代碼區(qū)、數(shù)據(jù)區(qū)、堆、棧,還有有一個段為符號表。

在編譯時,把版本等信息打包到符號表中,供程序運(yùn)行時使用。

  1. [root@localhost demo]# readelf -s client | grep main 
  2.     ...... 
  3.   1686: 00000000005608b0    16 OBJECT  GLOBAL DEFAULT   10 main.version 
  4.   1687: 00000000005608a0    16 OBJECT  GLOBAL DEFAULT   10 main.gitTag 
  5.   1688: 0000000000560890    16 OBJECT  GLOBAL DEFAULT   10 main.dateTime 
  6.     ...... 
  7.   2320: 00000000004eb2e8     7 OBJECT  GLOBAL DEFAULT    2 main.version.str 
  8.   2321: 00000000004ebba0    20 OBJECT  GLOBAL DEFAULT    2 main.dateTime.str 
  9.   2322: 00000000004eb2e0     7 OBJECT  GLOBAL DEFAULT    2 main.gitTag.str 

使用 readelf -s命令查看編譯好的Go二進(jìn)制文件符號表信息,可以明顯看到在編譯時寫入的三個變量。

其中,main.version、main.gitTag、main.dateTime 大小都為16,是指 在Go中的string類型結(jié)構(gòu)體大小。

  1. (gdb) ptype version 
  2. type = struct string { 
  3.     uint8 *str; 
  4.     int len; 
  5.  
  6. (gdb) ptype dateTime 
  7. type = struct string { 
  8.     uint8 *str; 
  9.     int len; 
  10.  
  11. (gdb) ptype gitTag 
  12. type = struct string { 
  13.     uint8 *str; 
  14.     int len; 

不知細(xì)心的你是否發(fā)現(xiàn),在符號表顯示的變量具體值 main.version.str、main.dateTime.str、main.gitTag.str長度都比實(shí)際多一個字節(jié)。

雖然目前Go實(shí)現(xiàn)了自舉,但是編譯Go編譯器的編譯器還是用C語言寫的

C語言字符串(字節(jié)數(shù)組)是非安全類型,使用尾零來標(biāo)識字符串結(jié)束。其中,尾零也占用一個字節(jié)。

尾零是 ASCII 第一個元素 0, 即:NUL

  1. (gdb) p version 
  2. $1 = "v0.0.1" 
  3.  
  4. (gdb) p dateTime 
  5. $2 = "2021-08-13,23:26:44" 
  6.  
  7. (gdb) p gitTag 
  8. $3 = "v0.0.1" 

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2020-09-14 08:56:30

Vue模板

2024-11-15 09:54:58

2017-04-11 08:36:09

iOS編譯應(yīng)用

2023-05-08 08:05:42

內(nèi)核模塊Linux

2021-10-26 13:18:52

Go底層函數(shù)

2019-12-06 13:59:37

代碼開發(fā)Python

2022-12-30 20:41:15

編譯原理case

2021-10-20 06:47:50

Elasticsear場景引擎

2013-12-30 11:21:31

Go編譯器

2021-05-13 18:53:34

Go編譯器Uber

2021-08-02 15:02:37

Go Excelize 開發(fā)

2021-03-16 08:56:35

Go interface面試

2010-01-15 10:16:50

CentOS rpm安

2023-12-25 07:46:01

Go語言循環(huán)

2021-07-28 07:53:21

Go語言拷貝

2023-03-09 11:32:00

MongoDB數(shù)據(jù)策略

2024-10-16 09:57:52

空結(jié)構(gòu)體map屬性

2021-06-07 23:51:16

MacGo服務(wù)

2017-05-26 11:07:17

Android框架代碼

2022-10-24 00:48:58

Go語言errgroup
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號