如何编写仅对新日志条目起作用的脚本

如何编写仅对新日志条目起作用的脚本

我觉得这应该是一件简单的事情,但我很难弄清楚。

我正在尝试编写一个脚本来监控某个 Apache 日志文件并采取一些特定操作。但我该如何监控日志文件呢?

每次将新行写入日志时,我都希望检查该条目以查看它是否与我要查找的内容匹配,如果匹配,则会发生 x。当我手动执行此操作时,我使用 cat 或 tail -f。我不想每 30 秒通过 cron 运行一次脚本并浏览整个日志(甚至最后 5 行),找出自上次运行脚本以来哪些行是新的,然后做其他事情。

有没有办法只检查日志中的单个新条目?

答案1

通过 cron 运行脚本但使用logtaillogtail2读取文件将避免每分钟读取整个文件。Logtail 会跟踪上次读取的位置,并在下次使用时跳转到该位置。

如果您想要立即对新的日志行采取行动,而不是在 cron 调用之间等待长达 59 秒,则必须使用tail -f或某些等效方法。

Janne 和 Khaled 的答案都似乎很好地解决了这个问题。

答案2

您可以使用已有的 Linux 工具,如tailgrepnamed 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更多细节。

相关内容