文章目录
- 前言
- 一、程序结构(功能实现的思路)
- 二、具体实现
- 1.功能函数实现
- 2.主程序实现
- 总结
前言
项目中有个从对端系统接入告警的实时进程,偶尔(一个月会有那么四五次)会报错挂掉,每天检查的话费事,因源码无法找到且业务无从了解,暂时不考虑重构,所以决定使用shell对进程进行监控,当进程异常时(从日志关键字判断),监控程序对被监控进程进行重启操作。
服务器环境:redhat6.5
一、程序结构(功能实现的思路)
因被监控进程会实时输出日志到nohup.out文件,故采取轮询的方式读取nohup.out内容,根据两次轮询时nohup.out的行号,确定搜索查询范围,若范围内出现特定的错误关键字则进行被监控进程的重启,若未出现,则记录检查时的nohup.out最大行号写入到checkpoint文件,作为下次轮询检查的起始检查点。
二、具体实现
1.功能函数实现
代码如下:
#!/bin/bash
# 脚本用于监控及重启集客设备告警进程:alcol_jzxn
# author@charlie
# date@2021-05-12
# 轮询的方式监控应用日志中的报错关键字,出现关键字则进行进程重启,未出现关键字则不做处理
# 程序入口设计:循环监控进程是否存在,存在则分析最新日志并确认是否进行重启,不存在则跳出循环
# 功能函数设计:
# isOnProcess -> 0 or 1:确认进程是否存在的函数,需传入进程关键字作为参数,存在则返回0,否则返回1。此次暂未使用该函数。
# checkWithLog -> 0 or 1:通过日志检查(报错关键字)的方式,需传入全路径日志名及报错关键字作为参数,确认进程是否要重启(调用重启函数),
# 需要重启则返回0,否则返回1
# rebootProcess -> 0 or 1:重启进程函数,需要传入全路径进程名作为参数,启动成功返回0并打印日志,否则返回1
function isOnProcess(){
# $1:进程关键字
echo "INTO FUNCTION--> isOnProcess" >> monitorLog${operateDate}.log
processId=`ps -ef | grep ${1} | awk '{if($(NF-1) != "grep") print $2}'`
if [ ! $processId ]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] process ${1} is not running >> monitorLog${operateDate}.log
return 1
else
echo [`date +'%Y-%m-%d %H:%M:%S'`] process ${1} is running >> monitorLog${operateDate}.log
return 0
fi
}
function rebootProcess(){
# $1:全路径进程名;$2:程序家目录
echo "INTO FUNCTION--> rebootProcess"
# alcol:此处换成你的进程关键字
oldPids=`ps -ef | grep alcol | awk '{if($(NF-1) != "grep") print $2}'`
pidCnt=`ps -ef | grep alcol | awk '{if($(NF-1) != "grep") print $2}' | wc -l`
if [ $pidCnt -eq 0 ]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] $1 is not running!Now to start it... >> monitorLog${operateDate}.log
source ${2}/setenv
nohup $1 &
sleep 3
newPids=`ps -ef | grep alcol | awk '{if($(NF-1) != "grep") print $2}'`
if [ ! $newPids ]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] Start Failed... >> monitorLog${operateDate}.log
return 1
else
echo [`date +'%Y-%m-%d %H:%M:%S'`] Start Over,New Pid is:$newPids >> monitorLog${operateDate}.log
return 0
fi
else
echo [`date +'%Y-%m-%d %H:%M:%S'`] $1 Old Pid is:${oldPids} >> monitorLog${operateDate}.log
echo ${oldPids} | xargs kill -9
sleep 3
# 开始重启
source ${2}/setenv
nohup $1 &
sleep 3
newPids=`ps -ef | grep alcol | awk '{if($(NF-1) != "grep") print $2}'`
newCnt=`ps -ef | grep alcol | awk '{if($(NF-1) != "grep") print $2}' | wc -l`
if [ $newCnt -eq 0 ]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] Start Failed... >> monitorLog${operateDate}.log
return 1
else
echo [`date +'%Y-%m-%d %H:%M:%S'`] Start Over,New Pid is:$newPids >> monitorLog${operateDate}.log
return 0
fi
fi
}
function checkWithLog(){
# $1:日志名; $2:报错关键字 $3:程序全路径名 $4:程序家目录 $5:程序运行时的日期
#获取上次检查点位置
if [[ ! -f monitorLog${5}.log ]]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] INIT LOG NOW >> monitorLog${5}.log
fi
echo "INTO FUNCTION--> checkWithLog:$#" >> monitorLog${5}.log
if [[ ! -f checkPoint.chk ]]
then
echo `cat ${1} | wc -l` >> checkPoint.chk
fi
read lastChk < checkPoint.chk
# 检查本次检查点与前次检查点是否一致
nowChk=`cat ${1} | wc -l`
if [[ "$nowChk" -eq "$lastChk" ]]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] Chkpoint is same,quit this loop check >> monitorLog${5}.log
return 1
else
# 检查是否存在指定异常
echo $2
isException=`sed -n "${lastChk},${nowChk}p" ${1} | grep ${2} | wc -l`
if [ ${isException} -gt 0 ]
then
echo [`date +'%Y-%m-%d %H:%M:%S'`] There Is ${isException} Exception Exist,Starting Reboot your Process ${3} >> monitorLog${5}.log
echo [`date +'%Y-%m-%d %H:%M:%S'`] Last CheckPoint is:${lastChk},Now Checkpoint is:${nowChk} >> monitorLog${5}.log
# 调用重启函数进行进程重启
rebootProcess ${3} ${4}
echo ${nowChk} > checkPoint.chk
return 0
else
echo [`date +'%Y-%m-%d %H:%M:%S'`] No ${2} Exception Exists >> monitorLog${5}.log
echo ${nowChk} > checkPoint.chk
return 1
fi
fi
}
2.主程序实现
代码如下:
# 主程序开始
PRO_DIR=/u03/Inspur/apps/Jk_Alarm_Collect
LOG_DIR=${PRO_DIR}
while true
do
operateDate=`date '+%Y%m%d'`
checkWithLog ${LOG_DIR}/nohup.out ORA-0 ${PRO_DIR}/alcol_jzxn ${PRO_DIR} $operateDate
sleep 10
done
此版是初版实现,功能测试正常,后续有空还会对脚本进行优化,提高程序的普适性。