从文本文件中连续读取数据的有效方法

时间:2010-07-28 23:04:55

标签: perl logging ftp

我们在FTP端点上有一个脚本,用于监控FTP守护程序发出的FTP日志。 目前我们所做的是有一个perl脚本基本上在文件上运行tail -F并将每一行发送到远程MySQL数据库,根据记录类型略有不同的列内容。

此数据库包含tarball名称/内容的内容表,以及包含所述包的FTP用户操作;下载,删除以及VSFTPd记录的所有其他内容。

我认为这特别糟糕,但我不确定什么更好。

替换的目标是尽快将日志文件内容放入数据库。我正在考虑做一些事情,比如创建一个FIFO /管道文件代替FTP日志文件的位置,所以我可以定期读取它,确保我从未读过两次相同的东西。假设VSFTPd会很好(我认为它不会,洞察力欢迎!)。

FTP守护进程是VSFTPd,我至少可以肯定他们的日志记录功能的范围是:xfer样式日志,vsftpd样式日志,两者,或者根本没有记录。

问题是,什么比我们已经做的更好,如果有的话?

4 个答案:

答案 0 :(得分:3)

老实说,我现在所做的事情并没有太大的错误。 tail -f效率很高。唯一真正的问题是,如果你的观察者脚本死了(这是一个用旋转日志文件解决的半难问题),它会失去状态。 CPAN上还有一个很好的File::Tail模块可以帮助您远离shellout并提供一些很好的自定义功能。

使用FIFO作为日志可以工作(只要vsftpd不尝试取消链接并在任何时候重新创建日志文件,它可能会这样做)但我看到它的一个主要问题。如果没有人从FIFO的另一端读取(例如,如果您的脚本崩溃,或者从未启动过),那么很短的时间后,所有对FIFO的写入都将开始阻塞。我还没有对此进行过测试,但很可能有logfile写入块将导致整个服务器挂起。不是一个非常漂亮的场景。

答案 1 :(得分:2)

您阅读不断更新的文件的问题是您希望继续阅读,即使在文件结束后也是如此。解决方案是重新寻找文件中的当前位置:

寻求FILEHANDLE,0,1;

这是我执行此类操作的代码:

open(FILEHANDLE,'<', '/var/log/file') || die 'Could not open log file';
seek(FILEHANDLE, 0, 2) || die 'Could not seek to end of log file';
for (;;) {
while (<FILEHANDLE>) {
    if ( $_ =~ /monitor status down/ ) {
            print "Gone down\n";
        }
    }
    sleep 1;
    seek FILEHANDLE, 0, 1;      # clear eof
}  

答案 2 :(得分:1)

您应该查看inotify(假设您使用的是基于posix的优秀操作系统),这样您就可以在更新日志文件时运行perl脚本。如果此级别的IO导致问题,您可以始终将日志文件保留在RAMdisk上,因此IO非常快。

这可以帮助您进行设置: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

答案 3 :(得分:0)

您可以将文件作为管道打开。

open(my $file, '-|', '/ftp/file/path');

while (<$file>) {
    # you know the rest
}

File :: Tail这样做,加上启发式睡眠和漂亮的错误处理和恢复。

编辑:第二个想法,如果你可以管理它,真正的系统管道会更好。如果没有,你需要找到你放在数据库中的最后一件事,并旋转文件,直到你进入数据库的最后一件事,无论你的进程何时开始。这并不容易实现,如果你无法确定你离开的地方,也可能无法实现。