1. 场景
在实际工作中,有这样一个场景:有一个定时任务,会定期去执行指定的工作(定时器在执行任务的同时,会打印相关的日志到日志文件中),但是可能因为一些原因,导致定时任务停止执行,这个时候就需要我们在最短的时间内收到告警通知,并修复任务。
2. 思路如下:
1)shell
脚本定时去扫描日志文件,找出定时任务最后一次打印日志的时间,然后计算该时间与当前系统时间的时间差。
2)当时间差超过阈值,调用python
脚本,推送告警通知(这里可以采用邮件,短信,以及IM
软件等,我下面的示例是调用我们公司内部IM软件的接口)
3. 实现
1)shell
脚本
思考:通常日志文件都很大,如果从头到尾的扫描日志文件,并找出最后一次定时任务打印的日志,耗时会很久;因此我们可以从日志文件尾部开始反向扫描,当我们第一次找到定时任务打印的日志行,即为定时任务最后一次打印的日志行。
代码如下:
#!/bin/bash
#日志文件路径
logfile=/home/test/prodduce/apache-tomcat/logs/
#获取日志文件最后一条push记录
# tac 反向查找日志;
# grep -m1 只打印出匹配的行
# awk '{print substr($0, 2, 19)}' 截取时间字段 ,这个取决于你的日志文件打印的格式
#我的定时任务打印的格式:[2019-03-24 11:47:08]-[INFO] com.app.busi.timer.task.MatchTask MatchTask starting……
lastest_push_date=`tac $logfile/catalina.out | grep -m1 'starting……' | awk '{print substr($0, 2, 19)}'`
#获取当前时间
now_date=`date +"%Y-%m-%d %H:%M:%S"`
#计算时间差,单位秒
date_dist=$(($(date +%s -d "$now_date") - $(date +%s -d "$lastest_push_date")))
#如果时间差超过5分钟,推送告警
if (($date_dist > 300));then
echo `date +'%Y/%m/%d %H:%M:%S'`" there is a error "
#/home/test/scrip/notice.py 所要执行的python脚本的位置
#$date_dist 把这个时间差传递给python脚本
/usr/bin/python /home/test/scrip/notice.py $date_dist
fi
2)python
脚本
# -*- coding: UTF-8 -*-
import urllib
import urllib2
import sys
import time
def sendAlter():
data = {
"to": "ertyrtyuertyurtyu",
# 注意看下面的,sys.argv[1] 此处为接收shell脚本传过来的值
"message": "timer has stopped {} seconds !!! please restart tomcat !".format(sys.argv[1]),
}
url = "接口地址"
data = urllib.urlencode(data)
headers = {'User-agent': 'PyMOTW (http://www.doughellmann.com/PyMOTW/)'}
request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request)
data = response.read()
print data
return True
if __name__ == '__main__':
sendAlter()
3)添加定时任务
执行crontab -e
,进入插入模式,输入:
# 每三分钟执行一次shell脚本
*/3 * * * * /home/test/scrip/scan.sh
4. 命令解释
下面对代码里用到的一些命令的详细解释
1)tac
,tac
是cat
的反转的形式,tac
从文件的最后一行往前读取.
2)grep -mNUM
,NUM
可以是任意数值,官方解释是Stop reading a file after NUM matching lines
,即当匹配到NUM行时,停止读取,我们的实例是grep -m1
,即当匹配到一行时,停止匹配。
3)awk
,awk '{print substr($0, 2, 19)}'
,$0
表示对该行进行处理,substr($0, 2, 19)
整体意思是从该行的第2个字符开始,截取19个字符结束。
4)date
,用来获取机器当前时间,如果需要格式化时间,可以加号(+)传参,也可用-d
显示指定字符串所指的日期与时间,%s
表示unix时间戳的秒数