end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転します

Proc::Daemonの全ファイルハンドルcloseにより、Log::Log4perl で「Cannot write to 〜: Bad file descriptor at 〜」

Proc::Daemonでperlデーモンプログラムを書いてみる - end0tknrのkipple - web写経開発
↑このエントリの関連です


Log::Log4perlでロギングしているアプリにProc::Daemonによるデーモン機能を追加したら、次のエラー。

Cannot write to '/home/endo/tmp/log4perl.log':
Bad file descriptor at
/usr/local/lib/perl5/site_perl/5.10.1/Log/Log4perl/Appender/File.pm line 245.


http://london.pm.org/pipermail/london.pm/Week-of-Mon-20080707/014502.html
はて?と思い、ググったところ↑このエントリを見つけたので、Proc::Daemonのsrc(↓)を読むと、それらしい記載があります。

# Close all file handles and descriptors the user does not want
# to preserve.
my $hc_fd; # highest closed file descriptor
close $FH_MEMORY;
foreach ( 0 .. OpenMax() ) {
    unless ( $dont_close_fd{ $_ } ) {
        if    ( $_ == 0 ) { close STDIN  }
        elsif ( $_ == 1 ) { close STDOUT }
        elsif ( $_ == 2 ) { close STDERR }
        else { $hc_fd = $_ if POSIX::close( $_ ) }
    }
}

http://search.cpan.org/perldoc?Proc%3A%3ADaemon

Proc::Daemonには dont_close_fh というoptionも用意されていましたが、うまくBad file descriptorを回避できないようなので、Proc::Daemonから?のログ出力は、STDERR に出力した方がよさそう。

ポイントは、Proc::Daemon::Init()でのログファイルを指定。

Proc::Daemon::Init({work_dir=> $WORK_DIR,
                    pid_file=> $PID_FILE,
                    child_STDOUT => "+>>$LOG_FILE",
                    child_STDERR => "+>>$LOG_FILE"});

と、IO::Handleのautoflushによる即時出力(バッファリング解除)

use IO::Handle;
STDERR->autoflush;
print STDERR $log_msg,"\n";

Log::Log4perlの出力先を child_STDOUTやchild_STDERR と同じにする方法もあったかもしれませんが、できないでしょうね。多分