Go编译时写入数据的原理
场景
公司线上运行的Go服务存在多个版本
时间:某天凌晨
事情:线上Go服务突然间 crash
紧急处理:重启Go服务
故障排查:查询日志,找出可能出现的堆栈信息以及追溯源码
问题 :线上同时存在多个版本,如何知道当前 crash 的程序属于哪个版本? 添加版本信息的两种方案
方案1,手动添加版本信息: package main import ( "flag" "fmt" ) // 下面三个变量,每次发版都要修改 var version = "v0.0.1" // 程序版本号 var gitTag = "v0.0.1" // git tag 号 var dateTime = "2021-08-14 10:00:00" // 编译生成时间 func main() { debugVerInfo := flag.Bool("ver", false, "show app version info") flag.Parse() if *debugVerInfo { fmt.Println("version is:", version) fmt.Println("dateTime is:", dateTime) fmt.Println("gitTag is:", gitTag) return } fmt.Println("do other thing") }
由于手动在代码中添加版本信息,所以在排查时可以查看到对应信息。 code ./client -ver version is: v0.0.1 dateTime is: 2021-08-14 10:00:00 gitTag is: v0.0.1
分析:
在很多公司甚至开源项目都会采用该方式,在代码中显式地添加版本等信息。 假设不经常发版或者发版周期比较长,则完全没问题 假设发版频繁,很大概率会出现版本信息的遗漏、错误 假设版本信息忘记更改,则查询出来的信息就是错的
针对以上情况,提出一个 问题 :Go是编译型语言,版本等信息是否可以在编译时,自动地打包到二进制文件中?
方案2,自动打包版本信息: package main import ( "flag" "fmt" ) var version = "v0.0.0"// 此处暂时只填写大的版本号 var gitTag string var dateTime string func main() { debugVerInfo := flag.Bool("ver", false, "show app version info") flag.Parse() if *debugVerInfo { fmt.Println("version is:", version) fmt.Println("dateTime is:", dateTime) fmt.Println("gitTag is:", gitTag) return } fmt.Println("do other thing") }
在编译时,打包版本等信息到Go的二进制文件中: go build -ldflags "-X main.version=v0.0.1 -X main.dateTime=`date +%Y-%m-%d,%H:%M:%S` -X main.gitTag=`git tag`" -o clientbuild 通过 -ldflags 的 -X 参数可以在编译时将值写入变量
变量格式: 包名称.变量名称=值
查看版本信息 code ./client -ver version is: v0.0.1 dateTime is: 2021-08-14 10:00:00 gitTag is: v0.0.1
优点: 无需代码中显式添加版本等信息 避免手动添加版本信息时,遗漏或者错误等情况发生 可使用持续集成工具自动把版本等信息打包到二进制文件中 原理
二进制文件在加载到内存中之后,整个内存空间会被划分为若干段。除了代码区、数据区、堆、栈,还有有一个段为符号表。
在编译时,把版本等信息打包到符号表中,供程序运行时使用。 [root@localhost demo]# readelf -s client | grep main ...... 1686: 00000000005608b0 16 OBJECT GLOBAL DEFAULT 10 main.version 1687: 00000000005608a0 16 OBJECT GLOBAL DEFAULT 10 main.gitTag 1688: 0000000000560890 16 OBJECT GLOBAL DEFAULT 10 main.dateTime ...... 2320: 00000000004eb2e8 7 OBJECT GLOBAL DEFAULT 2 main.version.str 2321: 00000000004ebba0 20 OBJECT GLOBAL DEFAULT 2 main.dateTime.str 2322: 00000000004eb2e0 7 OBJECT GLOBAL DEFAULT 2 main.gitTag.str
使用 readelf -s 命令查看编译好的Go二进制文件符号表信息,可以明显看到在编译时写入的三个变量。
其中, main.version 、main.gitTag 、main.dateTime 大小都为16,是指 在Go中的string类型结构体大小。(gdb) ptype version type = struct string { uint8 *str; int len; } (gdb) ptype dateTime type = struct string { uint8 *str; int len; } (gdb) ptype gitTag type = struct string { uint8 *str; int len; }
不知细心的你是否发现,在符号表显示的变量具体值 main.version.str 、main.dateTime.str 、main.gitTag.str 长度都比实际多一个字节。虽然目前Go实现了自举,但是编译Go编译器的编译器还是用C语言写的
C语言字符串(字节数组)是非安全类型,使用尾零来标识字符串结束。其中,尾零也占用一个字节。
尾零是 ASCII 第一个元素 0, 即:NUL(gdb) p version $1 = "v0.0.1" (gdb) p dateTime $2 = "2021-08-13,23:26:44" (gdb) p gitTag $3 = "v0.0.1"
心无旁骛,纵享沉浸前言我知道描述VR头盔的体验是非常很困难的,因为这就好比无论你怎么去给你的朋友吹爆HalfLifeAlyx,都不如让他戴上头盔,然后被猎头蟹给来那么一下)VR的快乐和只狼一样,看别
设立品控标准,规范万物可直播来源中工网工人日报原标题设立品控标准,规范万物可直播木须虫据澎湃新闻网报道,针对直播电商如何选品,浙江省日前发布直播电子商务选品和品控管理规范团体标准。该标准对直播带货的选品品控方
iPhoneSE3首摔屏幕够硬背板碎了iPhoneSE3已经开卖了一段时间,虽然用户风评并不是很好,但手机的质量看起来还是不错的。之前苹果曾表示该机采用了超坚固的玻璃面板,国外网友从6英尺(约1。8米)的高度摔落手机,
互动性和显示效果都一绝?OPPO的光追技术确实有亿点点不一样没想到手机上也能用上光追技术,近日,OPPO在游戏开发者大会,也就是我们常说的GDC上,展出手机端光线追踪技术落地的相关产品光追3D动态实时可交互壁纸,这个壁纸相较于传统的离线渲染
关于华为在俄手机大卖的启发最近俄乌战争,美欧对俄在手机方面进行了制裁,我们继而听到了华为大卖的消息,刚看了头条管理专家李江涛的分析,解析了华为之前受美制裁困境重重,但华为不服输,走上了自己研发的道路,现在华
买手机别扣扣嗖嗖,别掉入内存陷阱,6128G不要轻易尝试买手机别掉入内存陷阱,不要因为价格便宜,就购买6128G。128GB真的不够用!手机在我们生活中越来越重要,有很多的用途。第一,办公用途企业微信WPS等软件占用的内存也越来越多,第
三星两款旗舰收尾,12256G再降2000!有1。08亿像素4800mAh电池三星这个品牌,这两年在高端机产品链上的调整有点大。可能细心的用户都知道了,从去年开始,三星不再发布三星GalaxyNote系列常规旗舰,而是把更多资源和精力放在折叠屏上。现在我们看
科学家揭开蝙蝠回声定位演化之谜起源于蝙蝠共同祖先来源中国新闻网中新网昆明3月23日电(记者胡远航)回声定位是何时以及如何在蝙蝠中起源和演化的?来自中国科学院昆明动物研究所施鹏课题组的研究支持回声定位在蝙蝠类群中一次起源的假说,即
中兴被美国结束合规观察期,这到底是利好还是耻辱?前言根据相关媒体报道,与华为齐名的中国著名通信设备制造商中兴通讯,在本周二被美国法官裁定,同意结束其自2017年后的5年合规观察期。这意味着美国对中兴的制裁即将终止,中兴也能逐渐步
中芯国际熬出头了芯片的代工虽说是按照相关的图纸,相关的架构照搬照抄。但是,由于设备和制作工艺的先进性,让芯片代工也成功步入了高端领域,台积电更是凭借着这一个业务就名利双收。在我国大陆,其实也有这么
能保护聊天记录还不会被发现在聊天的软件随着网络大数据时代的到来,大家都开始重视个人的网络信息安全保护。特别是一些涉及个人信息的私密话题只能对指定的好友讨论的时候,私密社交就显得非常重要。好运吧加密聊天可以提高社交的门槛