用 shell 脚本做 restful api 接口监控
问题的提出
基于历史原因,公司有一个“三无”采集服务——无人员、无运维、无监控——有能力做的部门不想接、接了的部门没能力。于是就一直这样裸奔,直到前几天一个依赖于这个采集服务的大数据分析服务入口流量锐减,才发现居然是这个采集服务出问题了!而且问题不是简单的挂掉,而是这个采集服务给客户端下发的采集策略中,产品列表为空了!当时事出紧急,把所有产品开关挨个打开了一遍,算是临时解决了这个问题。事后复盘这个问题,从问题出现、到问题被感知到、再到问题被临时解决,这中间消耗的时间太长了,在新的采集服务上线之前,需要随时监控老的采集服务的接口状态,一旦有问题就可以立即处理。
问题的解决
对于后台开发或自动化测试来说,搞个监控是分分钟的事,对于我们这种客户端开发就不一样了,如果用 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),如果一切正常的话,你会得到下面这一堆数据:
|
本身是个 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 进行转换,不然可以直接用管道线连接啦),将解密后的数据输出到标准输出。经过上面的处理,这一坨数据就能被人类所识别了:
|
在网页里显示会自动换行,实际上这段输出只有两行,而第二行才是我们需要的。提取第二行后交给 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(不要问为什么,问就是请参考附录)。首先登录 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="[email protected]"
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: [email protected]
To: [email protected]
Cc: [email protected]
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 节。下面是经过一段时间后,脚本输出的日志:
|
输出太长,中间有省略。可以观察到 7.13 日 14:00 有一次报警 (不过后来证明是一次乌龙,汗~)
结语
来源:https://www.cnblogs.com/goodcitizen/p/striping_log_file_by_shell_scripts.html
-------- THE END --------
🍁
龙腾测试统招本科,可先就业后交费,没利息,不贷款,只需提供学信网认证资料。
真正的0元入学计划来了~