【问题标题】:Parsing lines from a log file containing date-time greater than something从包含大于某事的日期时间的日志文件中解析行
【发布时间】:2017-02-12 17:13:24
【问题描述】:

我有大约 100 MB 大小的日志文件,包含这样的行,开头包含日期时间信息:

[Tue Oct  4 11:55:19 2016] [hphp] [25376:7f5d57bff700:279809:000001] [] \nFatal error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting ')' in /var/cake_1.2.0.6311-beta/app/webroot/openx/www/delivery/postGetAd.php(12479)(62110d90541a84df30dd077ee953e47c) : eval()'d code on line 1

我有一个插件(nagios check_logwarn)只打印出那些包含一些错误字符串的行。以下是运行它的命令:

/usr/local/nagios/libexec/check_logwarn -d /tmp/logwarn -p /mnt/log/hiphop/error_20161003.log "^.*Fatal error*" 

我想根据日期时间进一步过滤掉,例如,11:55:10 之后的所有行。

我不确定是否为此使用正则表达式。以下是我目前所拥有的:

/usr/local/nagios/libexec/check_logwarn -d /tmp/logwarn -p /mnt/log/hiphop/error_20161003.log "^.*Fatal error*" | grep "15\:19\:1*"

但这只会过滤那些时间在第 15 小时的第 19 分钟的日志。

更新

我现在可以比较日期时间的时间部分。

/usr/local/nagios/libexec/check_logwarn -d /tmp/logwarn -p /mnt/log/hiphop/error_20161004.log "^.*Fatal error*" | awk '$4 > "14:22:11"'

如何比较一天部分?

更新 2 - 开放赏金

我不得不开一个赏金,因为我对 shell 没有太多的专业知识,我很快需要一个解决方案。

我被困在比较日期的部分。使用解决方案https://stackoverflow.com/a/39856560/351903,我将面临this problem。如果那是固定的,我会很高兴的。

我也愿意对此进行一些改进(我不介意输出是否有一些混乱的日志顺序)-

/usr/local/nagios/libexec/check_logwarn -d /tmp/logwarn -p /mnt/log/hiphop/error_20161004.log "^.*Fatal error*" | awk '$4 > "14:22:11"'

我查找了一些日期时间与时间戳的比较,但找不到有效的方法。

我无法继续 this question 中给出的内容。我看不到时间戳值 -

echo date -d '06/12/2012 07:21:22' +"%s"

不知道我错过了什么。

【问题讨论】:

标签: parsing grep nagios


【解决方案1】:

这使用参考时间戳并将日志文件中的时间戳与其进行比较;如果日志文件的时间戳更新,则打印该行:

awk -v refdate="$(date +'%s' -d 'Mon Oct 3 10:00:00 2016')" -F "[][]" '
    {
        cmd = "date +\047%s\047 -d \"" $2 "\""
        if ((cmd | getline val) > 0) {
            if (val > refdate)
                print
        }
        close(cmd)
    }
' infile

这是它的工作原理:

  • -v refdate="$(date +'%s' -d 'Mon Oct 3 10:00:00 2016')" 将给定日期(我们的参考日期)转换为纪元以来的秒数。
  • -F "[][]" 将字段分隔符设置为方括号,因此我们想要的时间戳就是 $2
  • "date +\047%s\047 -d \"" $2 "\"" 是我们要执行的 shell 命令;它变为date +'%s' -d "$2",即,它将日志文件时间戳转换为自纪元以来的秒数。 \047 是单引号。
  • cmd | getline val 评估 cmd 并将结果分配给 val,因此 val 现在保存日志文件中自纪元以来的时间戳,以秒为单位。
  • 我们用(cmd | getline val) > 0检查getline是否成功。
  • 如果getline 成功,if (val > refdate) print 会将日志文件时间戳与参考日期进行比较,如果日志文件时间戳较新,则打印该行。
  • close(cmd) 关闭管道。

参考文献

【讨论】:

  • 感谢您的回答。但是,如果我完全按照您提到的方式运行,我会得到 awk: cmd. line:10: fatal: cannot open file /tmp/logwarn' 用于阅读(成功)`。你的意思是像这样运行命令,还是用我的命令中的awk替换它,像这样-
  • /usr/local/nagios/libexec/check_logwarn -d /tmp/logwarn -p /mnt/log/hiphop/error_(date +'%Y%m%d').log "^.*Fatal*" | awk -v refdate="$(date +'%s' -d 'Mon Oct 3 10:00:00 2016')" -F "[][]" ' { cmd = "date +\047%s\047 -d \"" $2 "\"" if ((cmd | getline val) > 0) { if (val > refdate) print } close(cmd) } ' /tmp/logwarn
  • 对不起,我不是 shell 命令/bash 方面的专家。我将我发布的原始命令可视化的方式是,管道| 之前的整个内容会产生日志行的输出,awk 部分会进一步处理这些内容。我不明白/tmp/logwarn 在做什么。
  • @SandeepanNath 我认为这是您输入文件的名称,但它显然只是check_logwarn 的一个参数。您可以通过管道传递到命令,但是您不能在最后一个单引号之后指定文件名,因此awk -v [...] 'command' input_file(其中[...] 代表省略代码,command 代表单引号之间的所有内容)或other_command | awk -v [...] 'command' ,其中other_command 是您希望将其输出通过管道传输到 awk 的命令。
  • @SandeepanNath awk 与许多 unix 程序一样,接受来自文件的输入或通过管道来自标准输入的输入。如果您按照自己的意愿通过管道传输到它,则不得指定文件名,因此在您的情况下,您希望通过管道传输到我的答案中的命令,并且 not 在末尾添加 infile . infile 只是输入文件的通用名称,但您没有,您处理的是另一个命令的输出,而不是文件的内容。
【解决方案2】:

您需要可比较的日期表示

正则表达式可用于提取数据,但是将日期相互比较是一种糟糕的方式。您实际上需要将时间戳转换为类似的东西,例如 Epoch 时间或 DateTime 对象。如果要查找包含大于其他时间戳的时间戳的所有行,则需要解析出每行中的时间戳以进行比较。

Ruby 示例

#!/usr/bin/env ruby

require 'date'

# Convert your given timestamp to something comparable.
timestamp = DateTime.parse ARGV.first

# Loop over each line of your logfile.
File.open(ARGV.last).each_line do |line|
  # Use a rather naive regex to extract the timestamp from each line.
  next if line !~ /^\[.*?\]/

  # Print lines that contain a later timestamp than your target.
  puts line if DateTime.parse($&) > timestamp
end

脚本接受两个位置参数:

  1. 类似于 RFC 2822 的时间戳,带或不带时区偏移。
  2. 要解析的文件。

脚本然后比较每一行的时间戳,并且只打印早于作为参数传递的时间戳的行。如果您的真正意思是“晚于或等于”您的给定时间戳,您可以将比较从 > 修改为 >=,这可能更直观。

例如:

ruby /tmp/parse_log_dates.rb "Tue Oct  4 11:55:18 2016" /path/to/logfile

在您提供的非常有限的语料库上工作得很好。您的实际结果可能会有所不同,尤其是当您的日志文件实际上并未在每一行包含时间戳时。

【讨论】:

  • 感谢您的回复。但是,我没有使用 PHP(我是这方面的专家)来完成相同的任务,考虑当存在现有的 nagios 插件来查找错误提示关键字(致命错误等)时编写自己的东西是否明智.所以,我更喜欢 bash 命令解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-27
  • 2013-05-21
  • 2022-12-28
  • 2018-07-21
  • 2019-04-11
相关资源
最近更新 更多