【发布时间】:2015-06-26 19:25:19
【问题描述】:
我有一个使用 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 一起玩,那就太好了。任何帮助或 cmets 表示赞赏。谢谢!
编辑
根据以下答案,我能够使用提供的 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;
【问题讨论】: