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

Brothers,

I've searched long and read much on daemons and logging, including Proc::Daemon and Log::Log4perl on using Log::Log4perl and Proc::Daemon. Although that example suggests initializing Log4perl after calling Init() works, I haven't been able to get that to work, and I need to do logging both before and after going into the background.

Basically, I need to start up a daemon process, have it process configuration and command line arguments and log to a file via log4perl. If anything fails during initialization, it will exit with a non-zero code, letting the caller know that the startup didn't succeed. After initialization, the process will daemonize and continue logging, hopefully to the same log file.

The problem I have is that I need to process config and log before I daemonize, or I can't return a meaningful exit status to the caller. I need to continue to log after I deamonize, and would like to log to the same FileRotate appender/file.

I've tried quite a few combinations, and cannot get log4perl to initialize at all after Proc::Daemon::Init, regardless of whether I have attempted to initialize a log before the Init() call.

If I initialize before the Init() call, I get all the config logging I would expect, but then nothing (naturally, since Init() closed all the FDs). I have tried reinitializing after Init, but as I stated above above, no matter what I do, I can't get any logging after Init().

There must be a proven recipe out there for exactly this situation:

  1. start the process
  2. process args and config w/ logging
  3. exit with non-zero status on error
  4. go into background
  5. continue logging

I've looked at App::Daemon, which looks promising. But the description of how log4perl is initialize and handled is vague. What I don't understand is how to get access to the logger initialized by App::Daemon, and if the logger is available both before and after the call to daemonize().

Please, bless me Brothers, with the wisdom you hold within you.

  • Comment on Daemon w/ logging before and after background

Replies are listed 'Best First'.
Re: Daemon w/ logging before and after background
by chrestomanci (Priest) on Nov 23, 2010 at 17:03 UTC

    I have done this sort of thing myself with no difficulty. I suspect the reason you are having a problem, but I did not is because you are using Proc::Daemon and the like, but I wrote the code snippet to daemonize the process myself.

    I suspect that Proc::Daemon is closing ALL filehandles, including the one that log4perl just opened to the logfile, but that is just a guess.

    Here is an extract from one of my scripts that does what you need:

    # log4perl configuration. my $log4perlConf = q( # Normal messages to a log file. (That gets rotated once a week) log4perl.appender.logMessages=Log::Dispatch::FileRotate log4perl.appender.logMessages.filename=/var/log/logMessages.log log4perl.appender.logMessages.mode=append log4perl.appender.logMessages.max=5 # Number of logfiles kept be +fore deletion. log4perl.appender.logMessages.DatePattern=yyyy-ww log4perl.appender.logMessages.TZ=GMT log4perl.appender.logMessages.layout=Log::Log4perl::Layout::Patter +nLayout log4perl.appender.logMessages.layout.ConversionPattern=%d %p> %F{1 +}:%L %M - %m%n log4perl.logger = DEBUG, logMessages ); my $stop_now = 0; # Set to true by the signal ha +ndler. $SIG{'INT'} = sub { $stop_now = 1 }; sub main { # Setup log4perl Log::Log4perl::init(\$log4perlConf); my $logger = Log::Log4perl->get_logger(); my $opts = getArgs(); # Wrappers a call to Getopt::Long my $user_agent = LWP::UserAgent->new(); # Connect once & make sure it all works. fetchParseLog( $opts, $user_agent ); # Writes logging messages +via log4perl daemonize() if $opts->{'daemonize'}; # Main sleep, fetch & parse, sleep cycle. MAINLOOP: while( 0 == $stop_now ) { fetchParseLog( $opts, $user_agent ); # Writes logging messa +ges via log4perl sleep $sleep_time; } return 0; } sub daemonize { my $logger = Log::Log4perl->get_logger(); my $pid = fork(); defined $pid or $logger->logdie( "Can't fork: $OS_ERROR" ); if( $pid ) # Parent { exit 0; } elsif( 0 == $pid ) { # Child # Reopen filehandles to null, to prevent all output. open STDIN, '<', '/dev/null' or $logger->logdie( "Can't read + from /dev/null: $OS_ERROR" ); open STDOUT, '>>', '/dev/null' or $logger->logdie( "Can't writ +e to /dev/null: $OS_ERROR" ); open STDERR, '>>', '/dev/null' or $logger->logdie( "Can't writ +e to /dev/null: $OS_ERROR" ); # Become a session leader (no longer associated with the paren +t shell & TTY). setsid or $logger->logdie( "Can't star +t a new session: $OS_ERROR" ); # All done return; } }
Re: Daemon w/ logging before and after background
by zentara (Cardinal) on Nov 23, 2010 at 16:57 UTC
    Maybe the old script logdog would do what you need. It at least would give you a starting template on setting up the daemon process.

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh