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

Hi all, I have a cgi script that forks a child process. I close STDOUT so that the child can run when the browser is closed. Here's my question. Does the STDERR get closed automatically when I fork? Because I do not see any messages in the error logs. Where are the messages redirected and how do I capture them? Thanks a lot for your help.

Replies are listed 'Best First'.
Re: Fork child
by almut (Canon) on Dec 03, 2008 at 17:58 UTC
    Does the STDERR get closed automatically when I fork?

    That presumably depends on the web server...  Apache (mod_cgi), for example, does not close stderr (and your fork itself doesn't either), so any stuff written to stderr should by default end up in the web server's error log.

    OTOH, if you have a long running script that you want to dissociate from the Apache process serving the request, you'd have to close STDERR yourself — else the connection would 'hang' (as with STDOUT).  Or better yet, re-open STDERR to somewhere else.

      Usually just closing STDOUT worked. I never had to close STDERR explicitly. And I have been thinking about ways to capture error messages. The only thing I could come up with was to put an eval around the code, so that if something fails, I would know. But I would really like to be able to see warnings and such. Thanks!
        Usually just closing STDOUT worked.

        That's contrary to my experience with a default Apache / mod_cgi setup. I've always had to close both STDOUT and STDERR to cleanly dissociate a long running process.  But as it looks (you don't seem to find the error messages anywhere), there is some configuration variant, with which stderr is being closed for CGIs (or rather, no pipe for stderr is being set up in the first place...). In that case, you of course wouldn't have to close it another time.

        I have been thinking about ways to capture error messages

        Why not just reopen STDERR to some file?   Or maybe use CGI::Carp "fatalsToBrowser"; — or, more generally, carpout   ("fatalsToBrowser" of course wouldn't make sense for any long running process, as the connection to the browser would no longer be established in that case).

        Anyhow, more details about your configuration might help...

Re: Fork child
by JavaFan (Canon) on Dec 03, 2008 at 18:02 UTC
    Does the STDERR get closed automatically when I fork?
    It's really trivial to test:
    $ perl -wle 'fork; warn $$' 1787 at -e line 1. 1786 at -e line 1. $
    So, the answer is no.

    Also, from perldoc -f fork

    File descriptors (and sometimes locks on those descriptors) are shared, while everything else is copied.
Re: Fork child
by ig (Vicar) on Dec 03, 2008 at 19:58 UTC

    Update: I added a second write in the second child, after closing STDOUT in the child. The output to STDERR is still written to the error log.

    I was quite surprised that output from a child process, to both STDOUT and STDERR and long after the parent process had exited, was included in the response and written to the error log. This was on Apache on Linux (CentOS 5.2).

    #!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); print header, start_html(-title=>'fork test',); print "Parent start at " . localtime() . "<br>\n"; print STDERR "Parent start at " . localtime() . "\n"; if(my $pid = fork()) { sleep(5); print "Parent forking at " . localtime() . "<br>\n"; print STDERR "Parent forking at " . localtime() . "\n"; wait(); } else { print "First child at " . localtime() . "<br>\n"; print STDERR "First child at " . localtime() . "\n"; exit(0); } if(my $pid = fork()) { print "Parent forking again at " . localtime() . "<br>\n"; print STDERR "Parent forking again at " . localtime() . "\n"; } else { sleep(50); print "Second child at " . localtime() . "<br>\n"; print STDERR "Second child at " . localtime() . "\n"; close(STDOUT); sleep(50); print STDERR "Second child after STDOUT close at " . localtime +() . "\n"; exit(0); } print end_html; print "Parent exiting at " . localtime() . "<br>\n"; print STDERR "Parent exiting at " . localtime() . "\n"; exit(0);

    This produced the following in the browser:

    Parent start at Thu Dec 4 09:03:33 2008 First child at Thu Dec 4 09:03:33 2008 Parent forking at Thu Dec 4 09:03:38 2008 Parent forking again at Thu Dec 4 09:03:38 2008 Parent exiting at Thu Dec 4 09:03:38 2008 Second child at Thu Dec 4 09:04:28 2008

    And the following in the error log

    [Thu Dec 04 09:03:33 2008] [error] [client 127.0.0.1] Parent start at +Thu Dec 4 09:03:33 2008 [Thu Dec 04 09:03:33 2008] [error] [client 127.0.0.1] First child at T +hu Dec 4 09:03:33 2008 [Thu Dec 04 09:03:38 2008] [error] [client 127.0.0.1] Parent forking a +t Thu Dec 4 09:03:38 2008 [Thu Dec 04 09:03:38 2008] [error] [client 127.0.0.1] Parent forking a +gain at Thu Dec 4 09:03:38 2008 [Thu Dec 04 09:03:38 2008] [error] [client 127.0.0.1] Parent exiting a +t Thu Dec 4 09:03:38 2008 [Thu Dec 04 09:04:28 2008] [error] [client 127.0.0.1] Second child at +Thu Dec 4 09:04:28 2008 [Thu Dec 04 09:04:28 2008] [error] [client 127.0.0.1] File does not ex +ist: /var/www/html/favicon.ico, referer: http://localhost/cgi-bin/tes +t.pl [Thu Dec 04 09:05:18 2008] [error] [client 127.0.0.1] Second child aft +er STDOUT close at Thu Dec 4 09:05:18 2008
      The child I create does not write to the error log for some reason. Putting an eval around the code helps a great deal if you catch the error and immediately email the person who made the request. But I am going to redirect stderr to another log file and I think that will work. Thanks a lot.

        We would need more information about your server configuration and CGI script to determine why output to STDERR doesn't end up in the server's error log. If you want to pursue this, you should let us know your operating system, whether you are using mod_perl, fastCGI, etc. and versions of all the major components. And posting a small test script that exhibits the behaviour in your enviornment would be very helpful. You might also run the script I provided on your server and let us know what happens.

        On the other hand, if writing to another log file meets your needs, that's fine too.

Re: Fork child
by MidLifeXis (Monsignor) on Dec 03, 2008 at 17:59 UTC

    Which web server?

    --MidLifeXis

      Apache.