Last week I rolled out to our bleeding edge website an update to our application with new logging code, and it was good. Yesterday, for the first time since then, someone logged on and tried to update their email address, which caused the application to try an Email::Valid check, and it all went horribly wrong.

It turns out that Email::Valid implements its MX check using a fork-and-exec, and in the forked child it starts with:

open OLDERR, '>&STDERR' or croak "cannot dup stderr: $!"; open STDERR, '>&STDOUT' or croak "cannot redirect stderr to stdout: +$!";

Now our new logging code ties STDERR, and as a result this fails with the error q{Can't locate object method "OPEN" via package "NVC::Log::STDERR"}. And that's a good thing - I don't want the logging to leak into the child. But then I don't really want it dying either.

So, what should I do? It would be sorta handy if I could register a callback for fork(), but I don't think that's easily possible (and even overriding CORE::fork is unlikely to work, since the fork is actually implicit in the Email::Valid code within:

if (my $fh = new IO::File '-|') { ...

For the moment I've rolled up a new routine that suspends logging for the duration of the call to Email::Valid->address, but that doesn't feel like an ideal solution - I've no idea what other CPAN modules we're using that might have a fork() hidden under the machinery, and even if I did I don't really want to have to write individual protection for each one of them.

And I really like the effect I get by tying STDERR - I tried to write the logging code without that initially, and I was finding it very hard to get correct clean code; what I now have seems like a much more desirable approch if I can get over this one hurdle.

My tie class is very simple right now:

package NVC::Log::STDERR; use strict; sub TIEHANDLE { my $class = shift; bless {}, $class; } sub PRINT { my $self = shift; $log->die(join '', @_); }
and perhaps I can fix the problem by adding some methods (such as OPEN) to do the right thing, but I can't think what the right thing might be - I feel that the ideal solution would be to suspend logging just before any fork, and reenable it in the parent only just after, but I can't see how to get there from here.

Suggestions gratefully received,

Update: it doesn't solve the general problem, but I did discover that Email::Valid forks only as a fallback (using nslookup(1)) when it can't find Net::DNS; installing Net::DNS was enough to avoid the fork, and therefore allowed me to avoid suspending logging for the duration of the call.

Hugo


In reply to Catching fork() with tied STDERR by hv

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.