【问题标题】:How to pipe tail -f into awk如何将tail -f通过管道传输到awk
【发布时间】:2012-07-13 11:51:53
【问题描述】:

我正在尝试设置一个脚本,当某个字符串出现在日志文件中时会生成警报。

已经存在的解决方案每分钟对整个日志文件进行一次 greps,并计算字符串出现的频率,使用日志行的时间戳来仅计算前一分钟的出现次数。

我认为用尾巴做这个会更有效率,所以我尝试了以下方法作为测试:

FILENAME="/var/log/file.log"

tail -f $FILENAME | awk -F , -v var="$HOSTNAME" '
                BEGIN {
                        failed_count=0;
                }
                /account failure reason/ {
                        failed_count++;
                }
                END {
                        printf("%saccount failure reason (Errors per Interval)=%d\n", var, failed_count);
                }
'

但这只是挂起并且不输出任何内容。有人建议做这个小改动:

FILENAME="/var/log/file.log"

awk -F , -v var="$HOSTNAME" '
                BEGIN {
                        failed_count=0;
                }
                /account failure reason/ {
                        failed_count++;
                }
                END {
                        printf("%saccount failure reason (Errors per Interval)=%d\n", var, failed_count);
                }
' <(tail -f $FILENAME)

但它做同样的事情。

我正在使用的 awk(我已在上面的代码中进行了简化)工作正常,因为它在现有脚本中使用,grep "^$TIMESTAMP" 的结果通过管道传输到其中。

我的问题是,如何让 tail -f 与 awk 一起工作?

【问题讨论】:

  • 当您tail -f 时,您的 awk 脚本永远不会结束。所以你一直在计算错误,但从不打印任何东西。您需要运行 printf 并重置计数器的另一个条件(例如,检测到新的一天)。向我们展示您的日志样本,我们可以提出修复建议。

标签: awk tail


【解决方案1】:

假设您的日志如下所示:

Jul 13 06:43:18 foo account failure reason: unknown
 │   │    
 │   └── $2 in awk
 └────── $1 in awk

你可以这样做:

FILENAME="/var/log/file.log"

tail -F $FILENAME | awk -v hostname="$HOSTNAME" '
    NR == 1 {
        last=$1 " " $2;
    }
    $1 " " $2 != last {
        printf("%s account failure reason (Errors on %s)=%d\n", hostname, last, failed);
        last=$1 " " $2;
        failed=0;
    }
    /account failure reason/ {
        failed++;
    }
'

请注意,我已将其更改为 tail -F(大写 F),因为它处理日志老化。并非所有操作系统都支持此功能,但它应该可以在现代 BSD 和 Linuces 中使用。

这是如何工作的?

Awk 脚本由针对每一行输入评估的 test { commands; } 集组成。 (有两个特殊测试,BEGINEND,它们的命令分别在 awk 启动和 awk 结束时运行。在你的问题中,awk 从未结束,因此END 代码从未运行。)

上面的脚本包含三个测试/命令部分:

  • 首先,NR == 1 是一个仅在输入的第一行评估为真的测试。它运行的命令会为 last 变量创建初始值,将在下一节中使用。
  • 在第二部分中,我们测试“last”变量自评估的最后一行以来是否发生了变化。如果这是真的,则表明我们正在评估新一天的数据。现在是时候打印上个月的摘要(日志),重置我们的变量并继续前进了。
  • 在第三个中,如果我们正在评估的行与正则表达式 /account failure reason/ 匹配,我们会增加我们的计数器。

一清二楚? :-)

【讨论】:

  • +1 - 为了每天计算错误,您需要计算天数并进行除法。或者您可以将措辞更改为“昨天出错”并重置failed_count
  • 哦,看准了!不知道它在做什么,但是很好,谢谢!
  • @DennisWilliamson - 对,感谢您指出这一点。我已经更新了答案,因此代码将提供更清晰的结果。
  • 嘿,两年后重读这篇文章,我现在真的明白了,伟大的 :) 可能会看看我的旧问题的更多答案。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
相关资源
最近更新 更多