文章目录

  • 前言
  • 一、程序结构(功能实现的思路)
  • 二、具体实现
  • 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

此版是初版实现,功能测试正常,后续有空还会对脚本进行优化,提高程序的普适性。