hv has asked for the wisdom of the Perl Monks concerning the following question:
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:
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.package NVC::Log::STDERR; use strict; sub TIEHANDLE { my $class = shift; bless {}, $class; } sub PRINT { my $self = shift; $log->die(join '', @_); }
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
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Catching fork() with tied STDERR
by bluto (Curate) on Apr 30, 2004 at 15:29 UTC | |
|
Re: Catching fork() with tied STDERR
by bart (Canon) on Apr 30, 2004 at 20:10 UTC | |
by hv (Prior) on May 01, 2004 at 13:23 UTC | |
|
Re: Catching fork() with tied STDERR
by Anonymous Monk on Apr 30, 2004 at 16:51 UTC | |
by hv (Prior) on May 01, 2004 at 13:03 UTC |