这就是我计划为项目构建实用程序的方法:
logdump 将日志结果转储到文件日志。如果文件已存在,结果将附加到现有结果中(如果每月创建一个新文件,结果将附加到该月的同一文件中)。
extract 读取日志结果文件,以根据提供的参数提取相关结果。
问题是我不想等待 logdump 完成写入日志以开始处理它。同样,我需要记住,直到我已经阅读 log 开始提取更多信息,这不是我想要做的。
我需要实时结果,以便每当有什么内容添加到日志结果文件中时,提取将获得所需的结果。
提取所做的处理将是通用的(取决于它的一些命令行参数),但肯定是逐行的。
这涉及在文件被写入时读取文件,并在文件到达日志文件的末尾时连续监视文件以获取新的更新。
如何使用C或C ++或shell脚本或Perl执行此操作?
答案 0 :(得分:15)
tail -f
将从文件中读取并在达到EOF时监视它以获取更新,而不是直接退出。这是一种简单的方法来读取“实时”日志文件。可以这么简单:
tail -f log.file | extract
或者也许tail -n 0 -f
所以它只打印新行,而不是现有行。或tail -n +0 -f
显示整个文件,然后继续更新。
答案 1 :(得分:9)
传统的unix工具是tail -f
,它会一直读取附加到其参数的数据,直到你将其杀死为止。所以你可以做到
tail -c +1 -f log | extract
在unix世界中,从连续附加文件中读取已被称为“拖尾”。在Perl中,File::Tail模块执行相同的任务。
use File::Tail;
my $log_file = File::Tail->new("log");
while (defined (my $log_line = $log_file->read)) {
process_line($log_line);
}
答案 2 :(得分:6)
使用logdump
#! /usr/bin/perl
use warnings;
use strict;
open my $fh, ">", "log" or die "$0: open: $!";
select $fh;
$| = 1; # disable buffering
for (1 .. 10) {
print $fh "message $_\n" or warn "$0: print: $!";
sleep rand 5;
}
以及下面extract
的骨架,以获得您想要的处理。当logfile
遇到文件结尾时,logfile.eof()
为真。调用logfile.clear()
会重置所有错误状态,然后我们再次睡眠并重试。
#include <iostream>
#include <fstream>
#include <cerrno>
#include <cstring>
#include <unistd.h>
int main(int argc, char *argv[])
{
const char *path;
if (argc == 2) path = argv[1];
else if (argc == 1) path = "log";
else {
std::cerr << "Usage: " << argv[0] << " [ log-file ]\n";
return 1;
}
std::ifstream logfile(path);
std::string line;
next_line: while (std::getline(logfile, line))
std::cout << argv[0] << ": extracted [" << line << "]\n";
if (logfile.eof()) {
sleep(3);
logfile.clear();
goto next_line;
}
else {
std::cerr << argv[0] << ": " << path << ": " << std::strerror(errno) << '\n';
return 1;
}
return 0;
}
它并不像观看它那样有趣,但输出是
./extract: extracted [message 1] ./extract: extracted [message 2] ./extract: extracted [message 3] ./extract: extracted [message 4] ./extract: extracted [message 5] ./extract: extracted [message 6] ./extract: extracted [message 7] ./extract: extracted [message 8] ./extract: extracted [message 9] ./extract: extracted [message 10] ^C
我在输出中留下了中断,以强调这是一个无限循环。
使用Perl作为粘合语言,使extract
通过tail
从日志中获取行:
#! /usr/bin/perl
use warnings;
use strict;
die "Usage: $0 [ log-file ]\n" if @ARGV > 1;
my $path = @ARGV ? shift : "log";
open my $fh, "-|", "tail", "-c", "+1", "-f", $path
or die "$0: could not start tail: $!";
while (<$fh>) {
chomp;
print "$0: extracted [$_]\n";
}
最后,如果你坚持自己做重物,那就是related Perl FAQ:
如何在perl中执行tail -f?
首先尝试
seek(GWFILE, 0, 1);
语句
seek(GWFILE, 0, 1)
不会更改当前位置,但它会清除句柄上的文件结束条件,以便下一个<GWFILE>
使Perl再次尝试读取内容。如果这不起作用(它依赖于stdio实现的功能),那么你需要更像这样的东西:
for (;;) { for ($curpos = tell(GWFILE); <GWFILE>; $curpos = tell(GWFILE)) { # search for some stuff and put it into files } # sleep for a while seek(GWFILE, $curpos, 0); # seek to where we had been }
如果仍然无效,请查看
IO::Handle
中的clearerr
方法,该方法会重置句柄上的错误和文件结束状态。CPAN还有一个
File::Tail
模块。