shell 错误日志告警脚本

2023-10-23 14:39:36 浏览数 (1)

背景

服务器有敏感数据,不允许直接登陆服务器查看日志文件,也不允许使用如ELK等日志功能收集日志,所以只能使用最简单的办法,只将错误日志进行收集,然后通过应用的webhook进行收集。

思路

两种思路:

  1. 周期轮询
  2. 实时抓取

周期轮询

每隔一分钟去抓取一次,错误日志的内容上送webhook。 这样的好处是不会抓到过多的错误日志,但是也有个问题,有可能会错过关键的错误日志。 假如每一分钟一轮询,这一次查询刚好没有错误日志产生,而这一个轮询时刻的一分钟内产生了错误日志,就会错过。

如果到到轮询时刻去统计这一分钟到上一分钟之间的错误日志,是可以,但是如果错误在轮询完成后的这一刻发生,需要等到一分钟之后才会告警出来,缺乏实时性,如果对实时性要求不高可以使用这种方式。

实时抓取

这个思路很简单,就是实时抓取ERROR日志,有ERROR就推送webhook。 实现思路:

  1. 使用 tail 查询日志
  2. 倒序获取第一条
  3. 关键字可指定
  4. 过滤关键字

下面这个脚本实现以上的几个思路,算是一种简单的实现,我一直觉得脚本这东西不要写的太复杂,需要考虑后面的人维护的成本。另外脚本尽量使用python而不是shell,python更好维护,也利于扩展。写shell是因为历史原因。

三个关键的文件 errorword.txt 是错误关键字 exclude.txt 是排除的关键字 error_test.log 是错误日志

如果测试的话,使用 echo >> 重定向进去,如果是使用vim编辑保存的话,tail 会抓会量日志,不是脚本有问题。

代码语言:javascript复制
#!/bin/bash
IP=`echo $(curl -s ifconfig.me)`

ERROR_WORD=/data/errorword.txt
EXCLUDE=/data/exclude.txt
SLACK=https://hooks.slack.com/services/test_webhook
LOG_DIR=/Users/liukai/workspaces/temp/shell/alert/error_test.log

tail -Fn0 $LOG_DIR| 
while read line;do
    echo $line | grep -i -f $ERROR_WORD >/dev/null
    if [ $? -eq 0 ];then
       echo $line | grep -i -f $EXCLUDE >/dev/null
       ## white list
        if [ $? -gt 0 ]; then
            new_line=`echo $line | sed s/"//g`
            message='{
                "blocks": [
                    {
                        "type": "section",
                        "text": {
                            "type": "mrkdwn",
                            "text": "服务异常日志, IP: '"$IP"' n>'$new_line'n"
                        }
                    }
                    ]
                }'
            alert=`echo $message | sed s/'//g`
            #echo "$IP,$(date),$line" >> /Users/liukai/workspaces/temp/shell/alert/error_report.log
            curl -H "Content-Type: application/json" -X POST -d "$alert" $SLACK
       fi
    fi
done

改进版本

让任务在后台执行,上一个版本是用来验证这个功能,实际使用当中需要放到后台当中持续运行。 使用方式:

sh alert.sh start | stop

代码语言:javascript复制
#!/bin/bash
IP=`echo $(curl -s ifconfig.me)`
OPT=$1
ALERT_DIR=/data/alert
ERROR_WORD=$ALERT_DIR/errorword.txt
EXCLUDE=$ALERT_DIR/exclude.txt
LOG_DIR=/data/logs/tron.log
SLACK=https://hooks.slack.com/services/test_webhook

start() {
  nohup tail -Fn0 $LOG_DIR| 
    while read line;do
        echo $line | grep -i -f $ERROR_WORD >/dev/null
        if [ $? -eq 0 ];then
           echo $line | grep -i -f $EXCLUDE >/dev/null
           ## white list
            if [ $? -gt 0 ]; then
                new_line=`echo $line | sed s/"//g`
                message='{
                    "blocks": [
                        {
                            "type": "section",
                            "text": {
                                "type": "mrkdwn",
                                "text": "服务异常日志, IP: '"$IP"' n>'$new_line'n"
                            }
                        }
                    ]
                }'
                alert=`echo $message | sed s/'//g`
                curl -H "Content-Type: application/json" -X POST -d "$alert" $SLACK
           fi
        fi
    done &
}

stop() {
    kill -9 `ps -ef |grep 'tail -Fn0'|grep -v 'grep' |awk {'print $2'}`
}

if [[ $OPT == 'start' ]]; then
  start
  if [[ !? -eq 0 ]]; then
      echo "start alert"
  else
      echo "start fail"
  fi
elif [[ $OPT == 'stop' ]];then
    stop
    echo "stop alert"
fi

总结

尽量使用简单的脚本,不要让脚本变的复杂。

0 人点赞