我觉得这应该是一件简单的事情,但我很难弄清楚。
我正在尝试编写一个脚本来监控某个 Apache 日志文件并采取一些特定操作。但我该如何监控日志文件呢?
每次将新行写入日志时,我都希望检查该条目以查看它是否与我要查找的内容匹配,如果匹配,则会发生 x。当我手动执行此操作时,我使用 cat 或 tail -f。我不想每 30 秒通过 cron 运行一次脚本并浏览整个日志(甚至最后 5 行),找出自上次运行脚本以来哪些行是新的,然后做其他事情。
有没有办法只检查日志中的单个新条目?
答案1
通过 cron 运行脚本但使用logtail
或logtail2
读取文件将避免每分钟读取整个文件。Logtail 会跟踪上次读取的位置,并在下次使用时跳转到该位置。
如果您想要立即对新的日志行采取行动,而不是在 cron 调用之间等待长达 59 秒,则必须使用tail -f
或某些等效方法。
Janne 和 Khaled 的答案都似乎很好地解决了这个问题。
答案2
您可以使用已有的 Linux 工具,如tail
、grep
和named pipes
。首先,使用以下命令创建命名管道 (fifo):
$ mkfifo /tmp/myfifo
其次,创建一个简单的脚本,它将读取这个 fifo 文件。这是一个简单的例子:
#!/bin/bash
pipe=/tmp/myfifo
while true
do
if read line <$pipe; then
if [[ "$line" == 'quit' ]]; then
break
fi
echo $line
fi
done
echo "Reader exiting"
此脚本从命名管道读取并将行打印到标准输出,直到获得“退出”字样。这只是一个可以自定义的示例。
第三,用于tail
读取附加到 apache 日志文件的新行并将输出重定向到命名管道。
$ tail -n0 -F /var/log/apache2/access.log | grep some_text > /tmp/myfifo
选项-F
表示按名称跟踪文件,这应该使它不受 logrotate 的影响。因此,它将始终跟踪相同的文件名。表示-n0
不获取任何旧行。grep
对于仅定向相关行很有用。
使用此解决方案,您不需要任何 cron 作业。只需运行上面显示的脚本和 tail 命令即可。
答案3
如果您有syslog-ng
(可能rsyslogd
也会有) syslog-daemon,那么您可以使用它。
只需将其配置为关注 Apache 日志文件,或者配置 Apache 使用CustomLog
指令和将日志发送到 syslog 设备logger
。
Syslog-daemon 将使用模式匹配,如果找到匹配项,则执行 $foo。例如,在 syslog-ng 中,您可以设置一个日志文件钩子并按如下方式对其进行过滤:
source apache_log { file("/var/log/apache2/access.log"); };
filter apache_match { match("GET /evilscript.php"); };
然后 syslog-ng 调用外部脚本
destination apache_logmatch_script { program("/usr/local/bin/apachematch.pl"); };
最后把所有这些放在一起:
log { source(apache_log); filter(apache_match); destination apache_logmatch_script); };
如果使用这种技术,syslog-ng 将生成脚本背景,等待新内容出现。因此,您需要修改脚本以等待来自 STDIN 的输入;这是一个简短的 Perl 示例:
#!/usr/bin/perl -w
$|=1;
while (<>) {
printf "Stuff happened, I got this entry: %s!\n", $_;
}
除非我知道您想尝试这种技术,否则我不会进一步深入回答。
答案4
您可以使用 diff。将日志文件复制到临时文件。
对实时日志文件和临时文件进行对比。
对结果差异运行模式匹配。
这个想法来自 nagios check_log 插件。参见http://www.kilala.nl/Sysadmin/index.php?id=715更多细节。