下午好,
我有一个小的Perl脚本,它基本上模拟了Minecraft server.log上的tail -f
功能。该脚本检查某些字符串并以各种方式执行。
该脚本的简化版本如下:
#!/usr/bin/perl
use 5.010;
use warnings;
use strict;
my $log = "PATH TO LOG";
my $curpos;
open(my $LOGFILE, $log) or die "Cannot open log file";
# SEEK TO EOF
seek($LOGFILE, 0, 2);
for (;;){
my $line = undef;
seek($LOGFILE,0,1); ### clear OF condition
for($curpos = tell($LOGFILE); <$LOGFILE>; $curpos = tell($LOGFILE)){
$line = "$_ \n";
if($line =~ /test string/i){
say "Found test string!";
}
}
sleep 1;
seek($LOGFILE,$curpos,0); ### Setting cursor at the EOF
}
当我有一个测试服务器时,一切似乎工作正常。在生产中,server.log文件被轮换。当日志轮换时,脚本会保留原始文件,而不是替换它的文件。 即正在监视server.log,将server.log移动并压缩为logs / date_x.log.gz,server.log现在是一个新文件。
如何调整脚本以监控文件名“server.log”,而不是当前名为“server.log”的文件?
答案 0 :(得分:5)
您是否考虑过使用tail -F
作为脚本的输入:
tail -F server.log 2>/dev/null | perl -nE 'say if /match/'
这将观察指定的文件,将每一行传递给STDIN上的脚本。它将只正确跟踪server.log,如下所示:
echo 'match' >server.log
(由脚本匹配)
mv server.log server.log.old
echo 'match' >server.log
(也匹配)
您可以使用以下命令在Perl中打开tail -F
文件:
open(my $fh, '-|', 'tail -F server.log 2>/dev/null') or die "$!\n";
答案 1 :(得分:2)
您可以使用inode numbers检查stat()
的文件名和文件句柄。如果它们不同,则会旋转日志文件并重新打开文件以供阅读。
$readline
是iterator(由get_readline($file_name)
获得)透明地处理此类更改,并做“正确的事情”。
use strict;
use warnings;
sub get_readline {
my ($fname) = @_;
my $fh;
return sub {
my ($i1, $i2) = map { $_ ? (stat $_)[1] : 0 } $fh, $fname;
if ($i1 != $i2) {
undef $fh;
open $fh, "<", $fname or return;
}
# reset handle to current position
seek($fh, 0, 1) or die $!;
return wantarray ? <$fh> : scalar <$fh>;
};
}
`seq 11 > log_file`;
my $readline = get_readline("log_file");
print "[regular reading]\n";
print $readline->();
print "[any new content?]\n";
print $readline->();
`rm log_file; seq 11 > log_file`;
print "[reading after log rotate]\n";
print $readline->();
输出
[regular reading]
1
2
3
4
5
6
7
8
9
10
11
[any new content?]
[reading after log rotate]
1
2
3
4
5
6
7
8
9
10
11