我正在尝试设置一个脚本,当某个字符串出现在日志文件中时会生成警报。
已经存在的解决方案每分钟刷一次整个日志文件,并计算字符串出现的频率,使用日志行的时间戳仅计算前一分钟的出现次数。
我认为用尾巴做这个会更有效率,所以我尝试了下面的测试:
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”的结果通过管道输入。
我的问题是,如何让尾部-f与awk一起使用?
答案 0 :(得分:4)
假设您的日志看起来像这样:
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; }
个集合。 (有两个特殊测试,BEGIN
和END
,其命令分别在awk启动和awk结束时运行。在你的问题中,awk从未结束,因此END
代码从未运行过。)
上面的脚本有三个测试/命令部分:
NR == 1
是仅在第一行输入上评估为真的测试。它运行的命令会创建last
变量的初始值,在下一节中使用。/account failure reason/
匹配,我们会增加计数器。清除泥土? : - )