AnyEvent を使用して頻繁にファイルに書き出すスクリプトがあります。私が直面している問題を説明するために、次のサンプルを作成しました。
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
my $outputFile = 'out_test.log';
open my $out, ">>", $outputFile or die "Can't open output\n";
my $data = "test string"x50000 . "\n";
my $out_ready = AnyEvent->condvar;
my $out_hdl; $out_hdl = AnyEvent::Handle->new(
fh => $out,
on_error => sub {
my ($hdl, $fatal, $msg) = @_;
AE::log error => $msg;
$hdl->destroy;
$out_ready->send;
}
);
my $timer = AnyEvent->timer(
after => 0,
interval => 5,
cb => sub {
$out_hdl->push_write($data);
}
);
$out_ready->recv;
これはうまく機能しますが、しばらくするとファイル サイズが膨大になります。このような問題には logrotate を使用するため、次の logrotate 構成ファイルを作成しました。
/path/to/out_test.log {
size 2M
copytruncate
rotate 4
}
これもうまく機能し、上記の出力ファイルが 2M を超えるたびに、out_test.log.1 にローテーションされます。ただし、ローテーション直後に out_test.log を書き込むと、ファイルサイズはローテーションしたログファイルと同じになります。この動作と私が経験していることは、https ://serverfault.com/a/221343 で説明されています。
問題は理解できましたが、提供したサンプル Perl コードの問題を修正する方法がわかりません。
logrotate を使用してログ ローテーションを実装する必要はありませんが、実装することをお勧めします。スクリプトに実装するのが簡単であればそれもできますが、上記のサンプルを logrotate でうまく動作させることができればいいと思います。ヘルプやコメントをいただければ幸いです。ありがとう!
編集
以下の回答に基づいて、提供されたmonkeypatch ikegamiで物事を機能させることができ、Marc Lehmannのアドバイスに従ってネイティブperl I / Oを活用することができました。私のコード例は次のようになり、うまく機能します。さらに、これにより、logrotate の copytruncate ディレクティブの要件が削除されます。
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
my $outputFile = 'out_test.log';
open my $out, ">>", $outputFile or die "Can't open output\n";
my $data = "test string"x50000 . "\n";
my $cv = AnyEvent::condvar();
my $timer = AnyEvent->timer(
after => 0,
interval => 5,
cb => sub {
open my $out, ">>", $outputFile or die "Can't open output\n";
print $out $data;
close $out;
}
);
$cv->recv;