I have a script that writes out to a file on a frequent basis using AnyEvent. I've written the following sample to illustrate the issue I'm facing.
#!/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;
This works well, but the file size gets to be enormous after a while. We use logrotate for problems like this so I created the following logrotate configuration file.
/path/to/out_test.log {
size 2M
copytruncate
rotate 4
}
This also works well, and any time the above output file exceeds 2M it is rotated to out_test.log.1. However, when out_test.log is written to immediately after rotation, the file size is the same as the rotated log file. This behavior and what I'm experiencing is explained here: https://serverfault.com/a/221343
While I understand the issue, I don't know how to fix the problem in the sample Perl code I provided.
I don't have to implement log rotation via logrotate, but it would be preferred. If it's simple to implement in the script I can do that, but it would be nice if I could make the above sample play nice with logrotate. Any help or comments are appreciated. Thanks!
EDIT
Based on the answers below I was able to get things working with the monkeypatch ikegami provided as well as leveraging native perl I/O as per Marc Lehmann's advice. My example code looks like this and works well. Additionally this removes the requirement for the copytruncate directive in logrotate.
#!/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;