问题的提出
基于历史原因,公司有一个“三无”采集服务——无人员、无运维、无监控——有能力做的部门不想接、接了的部门没能力。于是就一直这样裸奔,直到前几天一个依赖于这个采集服务的大数据分析服务入口流量锐减,才发现居然是这个采集服务出问题了!而且问题不是简单的挂掉,而是这个采集服务给客户端下发的采集策略中,产品列表为空了!当时事出紧急,把所有产品开关挨个打开了一遍,算是临时解决了这个问题。事后复盘这个问题,从问题出现、到问题被感知到、再到问题被临时解决,这中间消耗的时间太长了,在新的采集服务上线之前,需要随时监控老的采集服务的接口状态,一旦有问题就可以立即处理。
问题的解决
对于后台开发或自动化测试来说,搞个监控是分分钟的事,对于我们这种客户端开发就不一样了,如果用 c/c++ 写代码倒是可以实现,但是一来慢、二来不灵活、三也不值当。于是重操旧业,用 shell 脚本搞起!话说我用的是 Windows 系统,为了在上面跑 shell 脚本,事先装了一个 msys2 系统 —— git bash,这段之前很多文章涉及过了,就不再赘述,就是对我的开发环境做个简要交待。
环境有了,现在整理一下我的思路,我希望做的是:访问后台 restful api 接口,从返回的结果中得到开启的产品数量,如果数量小于某个值,就向相关人员发送报警邮件,并记录日志。每隔一小时检查一次。
检查接口返回内容
访问 restful api 一般是通过 http 协议,这里我们选取 curl 做为拉取工具,写脚本如下:
curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4"
出于安全考虑,这里域名被我用星号代替了,后面的两个 url 参数分别是请求的类型(100 表示获取产品列表)和当前协议版本号(2.4),如果一切正常的话,你会得到下面这一堆数据:
{"message":"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","md5":"7cc552ea3a1f12c13f63f96f53aec29b27ab7b59542cfaac0c2938375156fdfd","result":true}
本身是个 json,有用的域是 message 字段,它本身又是加密的 (为毛不直接走 https?)。好吧,我们需要一个解密工具,对于客户端开发来说手到擒来,直接把测试用例改改就弄出来一个:
curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode
相比上面的语句,多了两个命令,其中 jq 是用来解析 json 的,负责将 message 字段提取出来,msys2 默认是不带这个命令的,可以访问以下网址获取:stedolan.github.com/jq/download/ ,安装后将命令所在目录添加到 PATH 环境变量、并重启系统后,就可以在 msys2 系统中使用 jq 了,不过我这里是直接把命令复制到了脚本所在目录,所以需要使用 ./jq 来指明;test-decode 就是我写的解密工具啦,它从命令行参数读取加密数据 (所以需要 xargs 进行转换,不然可以直接用管道线连接啦),将解密后的数据输出到标准输出。经过上面的处理,这一坨数据就能被人类所识别了:
after decode: {"products":[{"id":140,"name":"GrandDog","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":178,"name":"CubicostTRB","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":78,"name":"GTJ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":137,"name":"GMD2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":true},{"id":180,"name":"GDraw","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":276,"name":"GLC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":164,"name":"GUX","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":67,"name":"GCCP5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":261,"name":"GCCP6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":17,"name":"TME","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":25,"name":"GWS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":36,"name":"MOZIDIFFER","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":40,"name":"GMJ","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":44,"name":"GCL2013","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":45,"name":"GGJ2013","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":56,"name":"MD_GMA","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":75,"name":"GDQ2015","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":76,"name":"GQI2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":77,"name":"GJG2015","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":80,"name":"GMP2016","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":83,"name":"Revit2GFC4GMP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":100,"name":"GTJ2017CAD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":112,"name":"GYZB2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":114,"name":"BIM5D_PC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":115,"name":"GFYCM","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":125,"name":"GBCB","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":128,"name":"CubicostTAS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":129,"name":"GMD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":131,"name":"GAQ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":132,"name":"GBCB2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":133,"name":"GBS2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":134,"name":"GFYC2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":135,"name":"GFYCM2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":136,"name":"GMJ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":138,"name":"GSJ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":139,"name":"GJH2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":142,"name":"TeamViewer","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":148,"name":"ZPert","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":160,"name":"GBS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":162,"name":"GIR_C","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":163,"name":"TBQ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":167,"name":"GYJC2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":177,"name":"GSXGZT2016","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":181,"name":"TBQD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":182,"name":"TTED","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":183,"name":"TCFD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":188,"name":"GSCApp","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":200,"name":"GFYC","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":207,"name":"GDQ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":217,"name":"GO","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":218,"name":"AppGbmp","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":222,"name":"GQI2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":226,"name":"GDS2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":228,"name":"GLDTCS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":231,"name":"TenderGo","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":232,"name":"GDQ2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":233,"name":"SectionManual","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":234,"name":"BeamGo","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":235,"name":"GJG2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":236,"name":"RevitViewer","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":237,"name":"BIM5D_PC_TEST","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":238,"name":"BIM5D_PC_TRIAL","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":239,"name":"GEC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":240,"name":"GFYQ","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":241,"name":"RoadDesigner","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":242,"name":"CECS100G","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":243,"name":"GBES","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":244,"name":"Ceshi","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":245,"name":"dpUpdate","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":246,"name":"GFY4","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":248,"name":"GGPT","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":249,"name":"GMA2020","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":250,"name":"JZYK","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":251,"name":"GVB5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":252,"name":"GHW5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":253,"name":"GUp","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":254,"name":"BIM_COST","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":255,"name":"GICP5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":256,"name":"bim5d_basic","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":257,"name":"GWH5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":258,"name":"GFY4_2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":259,"name":"GDD2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":260,"name":"GCCP5_ShanDong_64","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":262,"name":"GSC6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":263,"name":"GCCP6_WP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":264,"name":"GEB6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":265,"name":"GSH6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":266,"name":"GTech2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":267,"name":"GPC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":268,"name":"GTJ2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":269,"name":"GDE2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":270,"name":"CubicostTIO","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":271,"name":"GCA5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":272,"name":"GLC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":273,"name":"GMT5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":274,"name":"GCN5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":275,"name":"GHC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":277,"name":"GVB6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":278,"name":"GJG2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":279,"name":"GJG","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":280,"name":"GAP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":281,"name":"GSTP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":283,"name":"TRS2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":284,"name":"TMEC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":285,"name":"CubicostTMEC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":286,"name":"GGF5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":287,"name":"GRE5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":310,"name":"GA_CloudPlugin","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false}],"msg_type":100}
在网页里显示会自动换行,实际上这段输出只有两行,而第二行才是我们需要的。提取第二行后交给 jq 解析出 products 域中的产品数据:
curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".products|.[]"
其中 jq ”.products|.[]“ 将把外层的元素去掉,对剩下的“纯纯“的内容进行 beautify 处理:
{ "id": 140, "name": "GrandDog", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 178, "name": "CubicostTRB", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 78, "name": "GTJ2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 137, "name": "GMD2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": true } { "id": 180, "name": "GDraw", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 276, "name": "GLC", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 164, "name": "GUX", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 67, "name": "GCCP5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 261, "name": "GCCP6", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": true } { "id": 17, "name": "TME", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 25, "name": "GWS", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 36, "name": "MOZIDIFFER", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 40, "name": "GMJ", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 44, "name": "GCL2013", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 45, "name": "GGJ2013", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 56, "name": "MD_GMA", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 75, "name": "GDQ2015", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 76, "name": "GQI2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 77, "name": "GJG2015", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 80, "name": "GMP2016", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 83, "name": "Revit2GFC4GMP", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 100, "name": "GTJ2017CAD", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 112, "name": "GYZB2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 114, "name": "BIM5D_PC", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 115, "name": "GFYCM", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 125, "name": "GBCB", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 128, "name": "CubicostTAS", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 129, "name": "GMD", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 131, "name": "GAQ2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 132, "name": "GBCB2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 133, "name": "GBS2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 134, "name": "GFYC2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 135, "name": "GFYCM2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 136, "name": "GMJ2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 138, "name": "GSJ2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 139, "name": "GJH2017", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 142, "name": "TeamViewer", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 148, "name": "ZPert", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 160, "name": "GBS", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 162, "name": "GIR_C", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 163, "name": "TBQ2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 167, "name": "GYJC2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 177, "name": "GSXGZT2016", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 181, "name": "TBQD", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 182, "name": "TTED", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 183, "name": "TCFD", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 188, "name": "GSCApp", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 200, "name": "GFYC", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 207, "name": "GDQ2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 217, "name": "GO", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 218, "name": "AppGbmp", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 222, "name": "GQI2018", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 226, "name": "GDS2017", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 228, "name": "GLDTCS", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 231, "name": "TenderGo", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 232, "name": "GDQ2018", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 233, "name": "SectionManual", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 234, "name": "BeamGo", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 235, "name": "GJG2018", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 236, "name": "RevitViewer", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 237, "name": "BIM5D_PC_TEST", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 238, "name": "BIM5D_PC_TRIAL", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 239, "name": "GEC5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 240, "name": "GFYQ", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 241, "name": "RoadDesigner", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 242, "name": "CECS100G", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 243, "name": "GBES", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 244, "name": "Ceshi", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 245, "name": "dpUpdate", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 246, "name": "GFY4", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 248, "name": "GGPT", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 249, "name": "GMA2020", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 250, "name": "JZYK", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 251, "name": "GVB5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 252, "name": "GHW5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 253, "name": "GUp", "aggre_status": true, "start": true, "enable_auto": false, "enable_filter": false } { "id": 254, "name": "BIM_COST", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 255, "name": "GICP5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 256, "name": "bim5d_basic", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 257, "name": "GWH5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 258, "name": "GFY4_2019", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 259, "name": "GDD2019", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 260, "name": "GCCP5_ShanDong_64", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 262, "name": "GSC6", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 263, "name": "GCCP6_WP", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 264, "name": "GEB6", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 265, "name": "GSH6", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 266, "name": "GTech2019", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 267, "name": "GPC5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 268, "name": "GTJ2021", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 269, "name": "GDE2019", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 270, "name": "CubicostTIO", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 271, "name": "GCA5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 272, "name": "GLC5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 273, "name": "GMT5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 274, "name": "GCN5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 275, "name": "GHC5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 277, "name": "GVB6", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 278, "name": "GJG2021", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 279, "name": "GJG", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 280, "name": "GAP", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 281, "name": "GSTP", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 283, "name": "TRS2021", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 284, "name": "TMEC", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 285, "name": "CubicostTMEC", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 286, "name": "GGF5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 287, "name": "GRE5", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false } { "id": 310, "name": "GA_CloudPlugin", "aggre_status": false, "start": true, "enable_auto": false, "enable_filter": false }
然后就可以得到下发产品列表中的产品数量了:
1 lines=$(curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".products|.[]" | wc -l) 2 # each item takes 8 line 3 prods=$(($lines/8)) 4 echo "product count : $prods" >> log.txt
没有找到 jq 怎么输出 json 数组元素个数,这里直接用 wc 计算行数除以 8 (每个产品占用 8 行)得到。同理得到密钥的数量(每个产品一个单独的密钥):
1 lines=$(curl -s "http://***.******.***/v3/server_status?type=101&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".keys|.[]" | wc -l) 2 # each item takes 4 line 3 keys=$(($lines/4)) 4 echo "keys count : $keys" >> log.txt
这两个数量必需一致,且大于某个域值,这里设定为 100.
1 limit=100 2 if [ $prods -ne $keys ]; then 3 echo "product count != key count, fatal error" >> log.txt 4 send_email "$prods" "$keys" "$limit" 5 exit 6 fi 7 8 if [ $prods -lt $limit ]; then 9 echo "products list too less, warning" >> log.txt 10 send_email "$prods" "$keys" "$limit" 11 exit 12 fi 13 14 echo "gux server ok" >> log.txt
如果有任何异常发生,通过 send_mail 函数来向相关人员发送告警邮件。
异常情况下发送报警邮件
铛铛铛~ 进入本文核心,现在如果接口中的产品数据为空或减少到特定值(产品一般只增加不减少),就需要通过邮件通知相关责任人了。这里使用的是 sendmail 命令,在 msys2 环境中,没有自带这个命令,需要事先安装 Windows 版本的压缩包、并设置 PATH 环境变量包含该命令所在的目录,重启机器后就可以在 msys2 环境中直接访问了。这里给一个下载链接:www.glob.com.au/sendmail/sendmail.zip。注意这个命令只是模拟 sendmail -t 选项,并不是原生的 sendmail 命令,但是用法和原生命令没什么区别。在开始看 send_email 函数之前,让我们先了解一些基本原理。
邮箱工作原理
你通过 qq 的账号给 126 发了一封邮件,它经历了哪些流程呢?请看下图
抛开复杂的协议不谈,单说整个流程,就是你先通过邮件客户端把邮件发到 qq 的邮件服务器,后者通过地址路邮给 126 的邮件服务器,最后你的邮件客户端再去后者的邮件服务器里拉取收到的邮件。对于 sendmail 命令而言,最主要就是进行发送账号的各种配置。
配置发送账号
在配置发送账号前,我们先选择一个可靠的账号,这里我选取 QQ(不要问为什么,问就是请参考附录)。首先登录 mail.qq.com
在邮箱的设置中找到账户相关设置,开通 IMAP/SMTP 服务:
开启后可以获取授权码,一个账户可以获取多个授权码,用在不同应用里:
出于安全考虑,这里把授权码隐掉了。
配置 sendmail 命令
有了账号和授权码就可以配置 sendmail 命令啦,下面打开命令目录内的 sendmail.ini 文件,加入以下几行:
1 ; configuration for fake sendmail 2 3 ; if this file doesn\'t exist, sendmail.exe will look for the settings in 4 ; the registry, under HKLM\Software\Sendmail 5 6 [sendmail] 7 8 ; you must change mail.mydomain.com to your smtp server, 9 ; or to IIS\'s "pickup" directory. (generally C:\Inetpub\mailroot\Pickup) 10 ; emails delivered via IIS\'s pickup directory cause sendmail to 11 ; run quicker, but you won\'t get error messages back to the calling 12 ; application. 13 14 smtp_server=smtp.qq.com 15 16 ; smtp port (normally 25) 17 18 smtp_port=25 19 20 ; SMTPS (SSL) support 21 ; auto = use SSL for port 465, otherwise try to use TLS 22 ; ssl = alway use SSL 23 ; tls = always use TLS 24 ; none = never try to use SSL 25 26 smtp_ssl=auto 27 28 ; the default domain for this server will be read from the registry 29 ; this will be appended to email addresses when one isn\'t provided 30 ; if you want to override the value in the registry, uncomment and modify 31 32 ;default_domain=mydomain.com 33 34 ; log smtp errors to error.log (defaults to same directory as sendmail.exe) 35 ; uncomment to enable logging 36 37 error_logfile=error.log 38 39 ; create debug log as debug.log (defaults to same directory as sendmail.exe) 40 ; uncomment to enable debugging 41 42 ;debug_logfile=debug.log 43 44 ; if your smtp server requires authentication, modify the following two lines 45 46 auth_username=2057975342@qq.com 47 auth_password=***************** 48 49 ; if your smtp server uses pop3 before smtp authentication, modify the 50 ; following three lines. do not enable unless it is required. 51 52 pop3_server= 53 pop3_username= 54 pop3_password= 55 56 ; force the sender to always be the following email address 57 ; this will only affect the "MAIL FROM" command, it won\'t modify 58 ; the "From: " header of the message content 59 60 force_sender= 61 62 ; force the sender to always be the following email address 63 ; this will only affect the "RCTP TO" command, it won\'t modify 64 ; the "To: " header of the message content 65 66 force_recipient= 67 68 ; sendmail will use your hostname and your default_domain in the ehlo/helo 69 ; smtp greeting. you can manually set the ehlo/helo name if required 70 71 hostname=
文中标黄的就是我们要加入的配置,这里授权码同样被我隐掉了(哎呀,邮箱暴露了~)。命令配置好了以后,就可以在 shell 脚本里调用 sendmail 命令了
使用 sendmail 命令发送邮件
终于可以回到我们之前提到的 send_mail 函数了,它有三个参数,分别是产品数量、密钥数量和最小限制值:
1 function send_email() 2 { 3 pc=$1 # product count 4 kc=$2 # key count 5 lm=$3 # count limit 6 from="2057975342@qq.com" 7 # for multiple receiver, not work 8 #to="yunh@******.com;anlj@******.com" 9 # using an array of receivers 10 to=("yunh@******.com" "anlj@******.com" "yuyf-a@******.com" "duanxd@******.com" "zhangcj-c@******.com" "linc@******.com" "sunyd@******.com" "zhangb-l@******.com") 11 subject="gux server exception" 12 content="gux restful api exception: \nproducts: $pc \nkeys: $kc \n\nproducts count != keys count \nor products count < $lm !!\n\n\n" 13 mail="From: \'gux monitor\' <$from>\nSubject: $subject\n\n$content" 14 15 for var in ${to[@]}; 16 do 17 mail=$(echo -e "To: <$var>\n$mail") 18 done 19 echo -e "$mail" >> mail.txt 20 echo -e "$mail" | sendmail -t 21 }
获取各个参数 (line 3~5) 用于后续拼接邮件正文 (line 12),对于 sendmail 命令来说 (line 20) 使用 -t 参数后允许将所有参数通过一个格式化的文本来设置,这个格式类似这样:
Subject: title
From: sender@mail.com
To: receiver@mail.com
Cc: copy@mail.com
body...
由两部分组成,邮件标题由 Subject(抬头)、From(发件人)、To(收件人)、Cc(抄送)……组成,两个空行之后是邮件正文。上面大段代码都是在设置这些内容 (line 6 ~ 13),注意为了减少对我 qq 账号的关注,这里对 From 域设置了别名 ‘gux monitor’,这样收到邮件就比较直观啦。下面是一次真实的报警邮件:
另外对于群发,不能简单的在 To 域设置多个接收人,而是要分别对每个接收人进行一次单独的 To 域设置(允许多个 To 域),这里使用 shell 数组对收件人进行了遍历处理 (line 10,15 ~ 18),最后一次性发送 (line 20),下面是打印到 mail.txt 里的邮件原文:
To: <zhangb-l@******.com> To: <sunyd@******.com> To: <linc@******.com> To: <zhangcj-c@******.com> To: <duanxd@******.com> To: <yuyf-a@******.com> To: <anlj@******.com> To: <yunh@******.com> From: \'gux monitor\' <2057975342@qq.com> Subject: gux server exception gux restful api exception: products: 0 keys: 0 products count != keys count or products count < 100 !!
注意由于遍历时是向邮件头添加 To 域,整个收件人列表是呈倒序排列的。然后效果就是上面截图的啦~
设置定时任务
最后就是把这个脚本设置成定时执行的任务了,这块可以参考之前写过的一篇文章 《查看博客园积分与排名趋势图的工具 》,第 3 节。下面是经过一段时间后,脚本输出的日志:
2020年07月 8日 16:00:01 product count : 103 keys count : 103 gux server ok 2020年07月 8日 16:55:15 product count : 103 keys count : 103 gux server ok 2020年07月 8日 17:00:01 product count : 103 keys count : 103 gux server ok 2020年07月 8日 18:00:01 product count : 103 keys count : 103 gux server ok 2020年07月 8日 19:00:01 product count : 103 keys count : 103 gux server ok
……
2020年07月13日 10:00:02 product count : 104 keys count : 104 gux server ok 2020年07月13日 11:00:01 product count : 104 keys count : 104 gux server ok 2020年07月13日 12:00:02 product count : 104 keys count : 104 gux server ok 2020年07月13日 13:00:02 product count : 104 keys count : 104 gux server ok 2020年07月13日 14:00:02 product count : 0 keys count : 0 products list too less, warning
输出太长,中间有省略。可以观察到 7.13 日 14:00 有一次报警 (不过后来证明是一次乌龙,汗~)
结语
后来查出问题的根因,居然是采集服务在和产品中心同步产品时(管理员登录的情况下),如果后者恰巧挂了,会导致前者同步不到数据,就会把所有产品开关重置掉!一个隐藏了 3+ years 的 bug 啊,教训深刻。不过话说回来,不管代码怎么 low,接口监控是不可少的。除了用来作接口监控,我还用 shell 脚本给其它服务做简单测试,例如验证升级服务能否正常下发版本、验证用户中心能否正常登录等等,凡是通过 restful api 提供服务的,基本可以通过 curl + jq 搞定,甚至通过 tcp 长连接实现的消息推送服务也可以用 shell 脚本来验证。不过这一系列的内容,因为涉及接口安全,我没法提供 git 下载地址(压根没有相应的 git 库),望大家理解,有需要的同学可以照猫画虎,把里面的接口换成自己能访问的,来动手验证一下。
参考
[2]. Using Sendmail on Windows
[5]. 不可或缺的 sendEmail
[6]. 配置mail命令的IMAP和SMTP,接收邮件和发送邮件
[10]. 命令行 JSON 处理工具 jq 的使用介绍
[11]. shell脚本处理JSON数据工具jq
[12]. HowTo: Install jq