3

こんにちは、

tail -f基本的に Minecraft の server.logの機能をエミュレートした小さな Perl スクリプトがあります。スクリプトは特定の文字列をチェックし、さまざまな方法で動作します。

スクリプトの簡略版は次のとおりです。

#!/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」を監視するようにスクリプトを変更するにはどうすればよいですか?

4

2 に答える 2

2

を使用して、ファイル名とファイルハンドルの両方のinode 番号を確認できますstat()。それらが異なる場合、ログ ファイルはローテーションされており、読み取りのためにファイルを再度開く必要があります。

$readlineこのような変更を透過的に処理し、「正しいこと」を行うイテレータ(によって取得) です。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
于 2013-11-07T14:03:24.630 に答える