使用zabbix根据时间监控多行格式的日志

2020-04-03 17:05:31

我们目前想使用zabbix每五分钟监控一个错误日志文件,如果监控到有错误产生,就发邮件告警。像标准的访问日志,如nginx的access log,一行表示一条日志,解析起来比较容易,但当日志不是一行一条时,如tomcat,glassfish的日志,如下:
[2015-07-17T14:24:04.552+0800] [glassfish 4.0] [SEVERE] [AS-WEB-CORE-00037] [javax.enterprise.web.core] [tid: _ThreadID=26 _ThreadName=http-listener-1(3)] [timeMillis: 1437114244552] [levelValue: 1000] [[
An exception or error occurred in the container during the request processing
java.lang.IllegalArgumentException
at org.glassfish.grizzly.http.util.CookieParserUtils.parseClientCookies(CookieParserUtils.java:353)
at org.glassfish.grizzly.http.util.CookieParserUtils.parseClientCookies(CookieParserUtils.java:336)
at org.glassfish.grizzly.http.Cookies.processClientCookies(Cookies.java:220)
at org.glassfish.grizzly.http.Cookies.get(Cookies.java:131)
at org.glassfish.grizzly.http.server.Request.parseCookies(Request.java:1911)
at org.glassfish.grizzly.http.server.Request.getCookies(Request.java:1505)
at org.apache.catalina.connector.Request.parseSessionCookiesId(Request.java:4077)
at org.apache.catalina.connector.CoyoteAdapter.postParseRequest(CoyoteAdapter.java:649)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:297)
]]

这个时候解析起来就相对复杂,我们可以使用如下脚本来取得最近五分钟的日志:

#!/bin/bash
 
# 取得前5分钟时间
LAST_MINUTE=$(date -d '-5 minute' +%H%M%S)
# 初始化日志条数
LOG_NUM=0
# 最大获取日志条数
MAX_LOG=3
# 初始化最终匹配日志
LOG_CONTENT=""
# 初始化包含时间行的匹配值
LOG_DATE_MATCH=false
# 设置日志路径
LOG_PATH="/data/log/glassfish/domain1/server.log"
 
while read line;do
 
     # 匹配包含时间的行
     if echo "$line" | grep -q '^[20';then
          # 根据包含时间行获取出特定时间格式,如181320
          date_time=$(echo $line | grep -E -o "[0-9]{2}:[0-9]{2}:[0-9]{2}" | tr -d ':')
 
          date_time=$(echo $date_time | sed 's/^0//')
          LAST_MINUTES=$(echo $LAST_MINUTES | sed 's/^0//')
          # 当前行的时间是否大于5分钟前的时间         
          if [[ "$date_time" -gt "$LAST_MINUTE" ]];then
               LOG_CONTENT="$LOG_CONTENT
$log_entry"
               ((LOG_NUM++))
               LOG_DATE_MATCH=true
               log_entry="$line
"
          else
               LOG_DATE_MATCH=false
               continue
          fi
 
     else
          # 只当前面日志时间满足条件时才设置log_entry值
          if $LOG_DATE_MATCH;then
               log_entry="$log_entry
$line"
          fi    
     fi
 
     # 限制最大获取行数
     if [[ "$LOG_NUM" -gt "$MAX_LOG" ]];then
          break
     fi
 
done < $LOG_PATH
 
# 输出全部日志
echo -n -e "$LOG_CONTENT"

前面的脚本按顺序读取的,但当日志文件比较大时,获取日志的效率就非常低了,所以推荐下面倒序读取日志的方法,更高效。

#!/bin/bash
 
# 取得前5分钟时间
LAST_MINUTE=$(date -d '-5 minute' +%H%M%S)
# 初始化日志条数
LOG_NUM=0
# 最大获取日志条数
MAX_LOG=3
# 初始化最终匹配日志
LOG_CONTENT=""
# 设置日志路径
LOG_PATH="/data/log/glassfish/domain1/server.log"
 
while read line;do
 
     # 匹配包含时间的行
     if echo "$line" | grep -q '^[20';then
          # 根据包含时间行获取出特定时间格式,如181320
          date_time=$(echo $line | grep -E -o "[0-9]{2}:[0-9]{2}:[0-9]{2}" | tr -d ':')
         
          # 当前行的时间是否大于5分钟前的时间   
          if [[ "$date_time" > "$LAST_MINUTE" ]];then
               ((LOG_NUM++))
               log_entry="$line
$log_entry"
               LOG_CONTENT="$LOG_CONTENT
$log_entry"
          else
               break
          fi
 
          log_entry=""
 
     else
          log_entry="$line
$log_entry"
     fi
 
     # 限制最大获取行数
     if [[ "$LOG_NUM" > "$MAX_LOG" ]];then
          break
     fi
 
done < <(tac $LOG_PATH)
 
# 输出全部日志
echo -n -e "$LOG_CONTENT"

之后就可以在zabbix添加一个监控项用来获取日志内容,触发器就使用{itemName.strlen(0)}#0表达式来检测获取到的日志内容是否不为空。itemName为监控项名称。

相关新闻

相关游戏