我正在尝试设置一个脚本,当某个字符串出现在日志文件中时会生成警报.
已经存在的解决方案每分钟刷一次整个日志文件并计算字符串出现的频率,使用日志行的时间戳仅计算前一分钟中的出现次数.
我认为用尾巴做这个会更有效率,所以我尝试了下面的测试:
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);
}
'
Run Code Online (Sandbox Code Playgroud)
但这只是挂起而不输出任何东西.有人建议这个小改动:
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)
Run Code Online (Sandbox Code Playgroud)
但这也是一样的.
我正在使用的awk(我在上面的代码中进行了简化)可以工作,因为它在现有脚本中使用,其中grep"^ $ TIMESTAMP"的结果通过管道输入.
我的问题是,如何让尾部-f与awk一起工作?
假设您的日志如下所示:
Jul 13 06:43:18 foo account failure reason: unknown
? ?
? ??? $2 in awk
??????? $1 in awk
Run Code Online (Sandbox Code Playgroud)
你可以做这样的事情:
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++;
}
'
Run Code Online (Sandbox Code Playgroud)
请注意,我已将其更改为tail -F(大写 F),因为它处理日志老化。并非每个操作系统都支持它,但它应该适用于现代 BSD 和 Linuces。
这是如何运作的?
awk 脚本由test { commands; }针对每行输入的评估集组成。(有两个特殊的测试,BEGIN并且END其运行的命令时AWK开始,当AWK两端,分别在你的问题,AWK永不落幕,所以END代码是永远不会运行。)
上面的脚本包含三个测试/命令部分:
NR == 1是仅在第一行输入上评估为真的测试。它运行的命令为last变量创建初始值,将在下一节中使用。/account failure reason/,我们增加我们的计数器。清如泥?:-)