获取两个日期之间的日志文件条目,只有致命的日期

时间:2018-06-26 14:41:48

标签: apache awk

我在网上搜索,所以没有人愿意做这项工作。 给定一个简单的Apache日志文件,例如 [2018年6月22日星期五11:46:13] [错误] [客户端xxxxxxxx] PHP解析错误:语法错误,第3554行的yyyyyyyyyyyyyyy中文件意外结束,引用网址:wwwwwwwwwwwwwwwwwwwwwwww [2018年6月22日星期五14:09:37] [错误] [客户端xxxxxxxx] PHP致命错误:在156行的yyyyyyyyyyyyyyyy中调用未定义的函数date_mysql2german(),引用网址:wwwwwwwwwwwwwwwwwwwwwwww [2018年6月25日星期一17:03:37] [错误] [客户端xxxxxxxx] PHP警告:mysql_num_rows()期望参数1为资源,第1409行的yyyyyyyyyyyyyyyy中给出的null,引用者:wwwwwwwwwwwwwwwwwwwwwwww [2018年6月26日星期二11:46:26] [错误] [客户端xxxxxxxx] PHP警告:mysql_num_rows()期望参数1为资源,在9390行的yyyyyyyyyyyyyyyyy中给出布尔值,引用网址:wwwwwwwwwwwwwwwwwwwwwwww [2018年6月26日星期二11:46:26] [错误] [客户端xxxxxxxx] PHP警告:mysql_num_rows()期望参数1为资源,在9432行的yyyyyyyyyyyyyyyy中给出布尔值,引用网址:wwwwwwwwwwwwwwwwwwwwwwww 我需要提取最近5分钟的所有“ PHP警告:”行(完整行)。 这是我到目前为止尝试过的 awk -v Date =“ $(日期” + [%a%b%d%H:%M:%S%Y“)” \ -v Date2 =“ $(date --date =” 5分钟前“”“ + [%a%b%d%H:%M:%S%Y”)“ \ '$ 4>日期&& $ 4

2 个答案:

答案 0 :(得分:2)

问题在于您比较字符串的方式过于文字化。日期按数据排序,但是awk按字典顺序进行比较(按日期顺序“ Jan” <“ Feb”,按字符串顺序则不是)。这里可以采用多种方法,但是我建议在UNIX时代进行比较。

$ tend=$(date "+%s")
$ tstart=$(date --date="5 minutes ago" "+%s")
$ awk -F '[][]' '!/PHP Warning/{next}
                 { cmd="date --date=\""$2"\" \"+%s\""
                   time=((cmd | getline line) > 0 ? line : -1)
                   close(cmd) }
                 (time == -1) { exit 1 }
                 (tend <= time && time <= tstart)
                ' tstart=$tstart tend=$tend <logfile>

注意::如果文件很大,这将对date执行大量调用。

另一种方法可能是从GNU awk调用mktime或将时间字符串重新格式化为 yyyymmddHHMMSS 。这使您可以对字符串使用字典顺序:

$ tstart=$(date -d="5 minutes ago" "+%Y%m%d%H%M%S"")
$ tend=$(date "+%Y%m%d%H%M%S"")
$ awk 'BEGIN{ month["Jan"]="01"; month["Feb"]="02"; month["Mar"]="03"
            month["Arp"]="04"; month["May"]="05"; month["Jun"]="06"
            month["Jul"]="07"; month["Aug"]="08"; month["Sep"]="09"
            month["Oct"]="10"; month["Nov"]="11"; month["Dec"]="12" }
      !/PHP Warning/{next}
      { time=$4; gsub(/:/,"",time); year=substr($5,1,4);
        date=sprintf(%4s%2s%0.2d%6s,year,month[$2],$3,time) }
      }
      (tstart <= date && tend <= date)
     ' tend=$tend tstart=$tstart  <logfile>

或根据Ed Morton的建议:

$ awk '!/PHP Warning/{next}
       { year=substr($5,1,4)
         month=(index("JanFebMarAprMayJunJulAugSepOctNovDec",$2)+2)/3
         time=$4; gsub(/:/,"",time);
         date=sprintf(%4s%0.2d%0.2d%6s,year,month,$3,time)
       }
       (tstart <= date && tend <= date)
      ' tend=$end tstart=$tstart <logfile>

相关文章可以在这里找到:Regex to match logfile custom date formats

答案 1 :(得分:1)

这对我来说是bash + gawk的工作:

#!/bin/bash

LC_ALL=C gawk -v limit=$(date --date="5 minutes ago" "+%s") '
function epoch(month, day, hhmmss, year) {
    gsub(/:/, " ", hhmmss)
    sub(/\]/, "", year)
    month = (index("JanFebMarAprMayJunJulAugSepOctNovDec", month) + 2) / 3
    return mktime(year" "month" "day" "hhmmss)
}
/PHP Warning/ && epoch($2, $3, $4, $5) > limit
' "test.log"

如果您还想包含致命错误,只需删除/PHP Warning/ &&或根据需要调整正则表达式即可(例如/Warning|error/或类似的东西)。