我想监控我的 vsftpd 日志并从日志中提取信息来处理已上传的文件。到目前为止,一切都很顺利,运行良好:
tail -n0 -F /var/log/vsftpd.log | while read line; do
if echo "$line" | grep -q 'OK UPLOAD:'; then
#do a bunch of processing stuff - this takes some time
fi
done
我开始进行一些规模测试,并一次上传了 500 个文件。由于某种原因,当您上传太多内容时,日志行会丢失或被截断。例如,典型的一行如下所示:
Sun Apr 7 09:08:51 2013 [pid 25409] [cam02430] OK UPLOAD: Client "206.132.183.201", "/20130407/09/20130407_090842D.avi", 531792 bytes, 426.14Kbyte/sec
但有时该行看起来像这样(如果没有完全缺失):
:08:51 2013 [pid 25409] [cam02430] OK UPLOAD: Client "206.132.183.201", "/20130407/09/20130407_090842D.avi", 531792 bytes, 426.14Kbyte/sec
它截断了日志的前几个字符。它不会对每一行都这样做,但会截断大部分行。而且很多行都丢失了。我想我遇到了处理无法及时完成的竞争条件。我该如何解决这个问题?
编辑 我想我有 3 个选择:
不要使用 tail,而要尝试使用 cron 作业/grep 等组合来检查日志中是否有新条目。我想这可能很棘手。我如何知道该日志中有什么新内容?
使用 monit 或同等工具监控文件更改。我不认为这是一个选项。文件被存储在带有时间戳的文件名的随机目录中。
logstash 或类似程序。我认为这些程序不符合我的需求。但也许有人知道其他情况。
现在我正专注于 #1,没有好的线索。因此,任何关于这方面的想法都将不胜感激。
答案1
您可以启动以防止分叉“grep”进程每一个在日志中的行中,通过像这样重写代码:
tail -n0 -F /var/log/vsftpd.log | grep 'OK UPLOAD:' | while read line ; do
#do a bunch of processing stuff - this takes some time
done
但我同意其他发帖者的观点,shell 并不适合处理繁重的文本/字符串。你应该考虑使用其他脚本引擎(至少是 awk,或者更好的是 perl 或 python)
答案2
如果您愿意放宽对 shell 脚本的限制,那么我在使用文件打开 '<' 选项的 Perl 方面拥有丰富的经验。
例如https://stackoverflow.com/questions/1425223/how-do-i-read-a-file-which-is-constantly-updating
答案3
正如@epoon建议,Perl 可能是一个不错的选择:
#!/usr/bin/env perl
open(FH,'<',$ARGV[0]) || die("Could not open file $ARGV[0]\n");
for (;;) {
while (<FH>) {
if (/OK UPLOAD/) { ## this is where you do your processing. As an example,
## I am collecting the file's info
/^(.+?)\s*\[pid\s*(\d+).+?\"([\d\.]+).+?\"(.+?)\".+?(\d+).+?\s([^\s]+)/;
my ($date,$pid,$client,$filename,$size,$rate) = ($1,$2,$3,$4,$5,$6);
print "On $date, process $pid uploaded file \"$filename\" of $size bytes from $client at $rate\n"
}
}
# eof reached on FH, but wait a second and maybe there will be more output
sleep 1;
seek FH, 0, 1; # this clears the eof flag on FH
}
运行此脚本/var/log/vsftpd.log
应该给出类似的输出
On Sat Apr 20 16:30:05 CEST 2013, process 25409 uploaded file "/20130407/09/20130407_090842D.avi" of 531792 bytes from 206.132.183.201 at 426.14Kbyte/sec
如果您具体说明想要用日志信息做什么,我会很乐意更新此信息。
答案4
您是否尝试过使用该--line-buffered
选项grep
?
tail -f /var/log/vsftpd.log | grep --line-buffered 'OK UPLOAD:' | while read line ; do
#do a bunch of processing stuff - this takes some time
done