Excalibor has asked for the wisdom of the Perl Monks concerning the following question:

Dear brother monks,

I have a program that's supposed to be daemon. Proc::Daemon works nicely for that.

But it's also supposed to leave logs. The whole of the project (of which this daemon is just a part) uses Log::Log4perl and we are very happy with it.

However there's something in Proc::Daemon::Init() that's spoiling Log::Log4perl...

Example follows:

use Log::Log4perl qw(get_logger); use Proc::Daemon; Log::Log4perl->init_and_watch( '/tmp/test_log_daemon.conf', 10 ); # Proc::Daemon::Init(); while (1) { my $logger = get_logger('TEST'); $logger->debug("Testing..."); sleep 5; } __END__ log4perl.rootLogger = DEBUG, FileAppndr1 log4perl.logger.TEST = DEBUG log4perl.appender.FileAppndr1 = Log::Log4perl::Appender::File log4perl.appender.FileAppndr1.filename = /tmp/test_log_daemon.log log4perl.appender.FileAppndr1.mode = append log4perl.appender.FileAppndr1.umask = 0006 log4perl.appender.FileAppndr1.layout = PatternLayout log4perl.appender.FileAppndr1.layout.ConversionPattern = %d{ISO8601} % +H %p> [%c] %F{1}(%L) %M - %m%n

The contents of the config file are shown... If you tail -f the log file, as it's now, it works, but if you uncomment the Init() line, it remains quiet. Other examples, reopening STDERR and using warn and SIGHUP and other tricks, do work, but I haven't manged to make Log::Log4perl work...

Any help really appreciated... Thanks!

--
our $Perl6 is Fantastic;

Replies are listed 'Best First'.
Re: Proc::Daemon and Log::Log4perl
by shmem (Chancellor) on Jun 28, 2006 at 11:48 UTC
    From the Manual Page of Proc::Daemon:

    The Proc::Daemon::Init function does the following:

    • 1 Forks a child and exits the parent process.
    • 2 Becomes a session leader (which detaches the program from the controlling terminal).
    • 3 Forks another child process and exits first child. This prevents the potential of acquiring a controlling terminal.
    • 4 Changes the current working directory to "/".
    • 5 Clears the file creation mask.
    • 6 Closes all open file descriptors.

    Note point 6. It closes all open file descriptors. Maybe exchanging two lines in your code does the trick:

    Proc::Daemon::Init(); Log::Log4perl->init_and_watch( '/tmp/test_log_daemon.conf', 10 );

    Don't know it it works (just an idea), maybe Log::Log4perl->init_and_watch() reopens STDERR or such.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      This does work for Proc::Daemon. Anything you want to do that involves file descriptors should be setup after the Init, which avoids a lot of problems. For example, what if your process forks several times, and each child then runs Proc::Daemon::Init()? They will all inherit the same filehandle, which can be annoying for some modules (if I recall correctly the biggest problem with Log::Log4perl is likely to be log entries that overlap) and disastrous for others (DBI handles in particular are something you want to make sure that your child processes aren't trying to share).


      We're not surrounded, we're in a target-rich environment!

      Yes! That worked!

      And it also worked on the project, once I remembered the ->init_and_watch() method is called within an Initialization module which is use()d in every other module... I simply called our init() function after the Proc::Daemon::Init() call and it worked perfectly...

      Thanks a bunch to all, you're fantastic!

      --
      our $Perl6 is Fantastic;

Re: Proc::Daemon and Log::Log4perl
by Corion (Patriarch) on Jun 28, 2006 at 11:44 UTC

    Looking at the source code of Proc::Daemon, the relevant code has potential for failures but doesn't check the results:

    sub Init { my $oldmode = shift || 0; my($pid, $sess_id, $i); ## Fork and exit parent if ($pid = Fork) { exit 0; } ## Detach ourselves from the terminal croak "Cannot detach from controlling terminal" unless $sess_id = POSIX::setsid(); ## Prevent possibility of acquiring a controling terminal if (!$oldmode) { $SIG{'HUP'} = 'IGNORE'; if ($pid = Fork) { exit 0; } } ## Change working directory chdir "/"; ## Clear file creation mask umask 0; ## Close open file descriptors foreach $i (0 .. OpenMax) { POSIX::close($i); } ## Reopen stderr, stdout, stdin to /dev/null open(STDIN, "+>/dev/null"); open(STDOUT, "+>&STDIN"); open(STDERR, "+>&STDIN"); $oldmode ? $sess_id : 0; }

    There are a couple of possibilities for you to check:

    1. The code closes all files currently open. From how I understand Log::Log4Perl::FileAppender, it opens the file once and then tries to use the filehandle it got from that. So maybe you need to reopen your log files after having become a daemon.
    2. The code sets the umask to 0, so you might need to reset it in your daemon code to some sensible value if you're trying to create new files
    3. The code resets SIGHUP, so whatever you're doing with SIGHUP might conflict with that.
    4. The Proc::Daemon code doesn't check for the result of chdir("/") - maybe you are not allowed to set your directory to / - this should be checked but is likely not the cause of your problems.

    For more debugging information, you should maybe reopen STDERR to a log file to which you warn (instead of using Log::Log4Perl) - I expect some print to closed file handle messages here.