Bot-Cobalt
view release on metacpan or search on metacpan
lib/Bot/Cobalt/Logger/Output/File.pm view on Meta::CPAN
my ($self) = @_;
my $fh;
unless (sysopen($fh, $self->file, $self->mode, $self->perms) ) {
warn(
"Log file could not be opened: ",
join ' ', $self->file, $!
);
return
}
binmode $fh, ':utf8';
$fh->autoflush;
$self->[INODE] = ( stat $self->file )[1]
unless $self->[RUNNING_IN_HELL];
$self->[HANDLE] = $fh
}
sub _close {
my ($self) = @_;
return 1 unless $self->_is_open;
close $self->[HANDLE];
$self->[HANDLE] = undef;
1
}
sub _is_open {
my ($self) = @_;
$self->[HANDLE]
}
sub _do_reopen {
my ($self) = @_;
## Are we on a stupid system or dealing with a not-open file?
return 1 unless $self->_is_open;
unless ( $self->[RUNNING_IN_HELL] ) {
## Do the inodes match?
return if -e $self->file
and $self->[INODE] == ( stat $self->file )[1];
}
1
}
sub _write {
my ($self, $str) = @_;
if ($self->_do_reopen) {
$self->_close;
$self->_open or warn "_open failure" and return;
}
## FIXME if flock fails, buffer and try next _write up to X items ?
my $timer = 0;
until ( flock($self->[HANDLE], LOCK_EX | LOCK_NB) ) {
if ($timer > FLOCK_TIMEOUT) {
warn "flock failure for '@{[$self->file]}' ('$str')";
return
}
sleep 0.01;
$timer += 0.01;
}
print { $self->[HANDLE] } $str;
flock($self->[HANDLE], LOCK_UN);
$self->_close if $self->[RUNNING_IN_HELL];
1
}
1;
__END__
=pod
=head1 NAME
Bot::Cobalt::Logger::Output::File - Bot::Cobalt::Logger file output
=head1 SYNOPSIS
$output_obj->add(
'MyFile' => {
type => 'File',
## Required:
file => $path_to_log,
## Optional:
# perms() defaults to 0666 and is modified by umask:
perms => 0666,
# mode() should be Fcntl constants suitable for sysopen()
# defaults to O_WRONLY | O_APPEND | O_CREAT
mode => O_WRONLY | O_APPEND | O_CREAT,
},
);
See L<Bot::Cobalt::Logger::Output>.
=head1 DESCRIPTION
This is a L<Bot::Cobalt::Logger::Output> writer for logging messages to a
file.
The constructor requires a L</file> specification (the path to the actual
file to write). L</perms> or </mode> can also be set at construction
time but are optional.
The log file is kept open persistently, but closed and reopened if the
file's inode has changed or the file has disappeared. This doesn't apply
on Windows, which has no concept of inodes; an open-write-close cycle
will be executed for each logged message on systems without useful inode
details, in order to ensure messages are going to the expected file.
Attempts to lock the file for every write; if a lock cannot be obtained after
half a second, falls back to C<warn>ing with the log message included.
Expects UTF-8.
( run in 0.588 second using v1.01-cache-2.11-cpan-5837b0d9d2c )