shell脚本定时监控日志报警

shell脚本定时监控日志报警

最近遇到一个需求,需要监控服务器错误日志的情况,以便及时发现服务器异常,在网上找了一圈后发现了这一篇文章,shell脚本定时监控日志报警 ,经过修改后符合我们项目的要求,主要修改了获取日志文件列表的方式,使它支持多目录监控,使用时需要配置好 /etc/mail.rc 使之可发送邮件,再结合 Crontab 即可实现定时监控:
原程序:monitor.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash
#记录上一次的行数
Last_num_d=/tmp/monitor/lastnum
#日志目录
Log_directory=/usr/local/nginx/logs
#ERROR log 临时存放目录
Error_log=/tmp/monitor/errorlog
#目录判断
d_judge(){
[ ! -d $1 ] && mkdir -p $1
}
d_judge $Last_num_d
d_judge $Error_log
for logfile in `ls $Log_directory |grep log |grep -v access` ; do
#for logfile in `ls $Log_directory` ; do
#先判断当前日志目录是否为空,为空则直接跳过
[ ! -s $Log_directory/$logfile ] && echo "`date` $logfile is empty" && continue
#判断记录上一次检查的行数的文件是否存在,不存在则给一个初始值
[ ! -f "$Last_num_d/$logfile" ] && echo 1 > $Last_num_d/$logfile
#将上一次值赋给变量
last_count=`cat $Last_num_d/$logfile`
#将当前的行数值赋给变量
current_count=`grep -Fc "" $Log_directory/$logfile`
#判断当前行数跟上一次行数是否相等,相等则退出当前循环
[ $last_count -eq $current_count ] && echo "`date` $logfile no change" && continue
#由于日志文件每天都会截断,因此会出现当前行数小于上一次行数的情况,此种情况出现则将上一次行数置1
[ $last_count -gt $current_count ] && last_count=1
#截取上一次检查到的行数至当前行数的日志并检索出有ERROR的日志,并重定向到相应的ERROR日志文件
sed -n "$last_count,$current_count p" $Log_directory/$logfile | grep -i ERROR >> $Error_log/$logfile && echo "`date` $logfile error " || echo "`date` $logfile changed but no error"
#判断ERROR日志是否存在且不为空,不为空则说明有错误日志,继而发送报警信息,报警完成后删除错误日志
[ -s $Error_log/$logfile ] && echo -e "$HOSTNAME \n `cat $Error_log/$logfile`" | mail -s "$logfile ERROR" xxxxxxx@qq.com && rm -rf $Error_log/$logfile
#结束本次操作之后把当前的行号作为下一次检索的last number
echo $current_count > $Last_num_d/$logfile
done

修改后:monitor_md.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash
#记录上一次的行数
Last_num_d=/tmp/monitor/lastnum
#日志目录 可以是某目录如:Log_directory=/root/test,或者是多个目录,用空格隔开Log_directory=“/root/test /root/test1”
Log_directorys="/mnt/harddrive/logs/app1/error /mnt/harddrive/logs/app2/error /mnt/harddrive/logs/app3/error"
#ERROR log 临时存放目录
Error_log=/tmp/monitor/errorlog
#目录判断
d_judge(){
[ ! -d $1 ] && mkdir -p $1
}
d_judge $Last_num_d
d_judge $Error_log
for Log_directory in $Log_directorys ;do
# 所有日志log文件,除了带 access 的文件,此处的 awk 作用为查出全路径
for logfile in `ls -1 $Log_directory |awk '{print i$0}' i=$Log_directory'/' |grep log |grep -v access` ; do
#for logfile in `ls $Log_directory |grep log |grep -v access` ; do # 这是查出路径
#for logfile in `ls $Log_directory` ; do
# 文件名称不能带斜杠/,所以把文件名转换成不带斜杠的
logfilemarkfile=`echo $logfile |awk '{gsub("/","-") ; print $0}'`
#先判断当前日志目录是否为空,为空则直接跳过
[ ! -s $logfile ] && echo "`date` $logfile is empty" && continue
#判断记录上一次检查的行数的文件是否存在,不存在则给一个初始值
[ ! -f "$Last_num_d/$logfilemarkfile" ] && echo 1 > $Last_num_d/$logfilemarkfile
#将上一次值赋给变量
last_count=`cat $Last_num_d/$logfilemarkfile`
#将当前的行数值赋给变量
current_count=`grep -Fc "" $logfile`
#判断当前行数跟上一次行数是否相等,相等则退出当前循环
[ $last_count -eq $current_count ] && echo "`date` $logfile no change" && continue
#由于日志文件每天都会截断,因此会出现当前行数小于上一次行数的情况,此种情况出现则将上一次行数置1
[ $last_count -gt $current_count ] && last_count=1
#截取上一次检查到的行数至当前行数的日志并检索出有ERROR的日志,并重定向到相应的ERROR日志文件
sed -n "$last_count,$current_count p" $logfile | grep -i ERROR >> $Error_log/$logfilemarkfile && echo "`date` $logfile error " || echo "`date` $logfile changed but no error"
#判断ERROR日志是否存在且不为空,不为空则说明有错误日志,继而发送报警信息,报警完成后删除错误日志
[ -s $Error_log/$logfilemarkfile ] && echo -e "$HOSTNAME \n `cat $Error_log/$logfilemarkfile`" | mail -s "$logfile ERROR" xxxxxxx@qq.com && rm -rf $Error_log/$logfilemarkfile
#结束本次操作之后把当前的行号作为下一次检索的last number
echo $current_count > $Last_num_d/$logfilemarkfile
done
done