Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Prevent my STDERR logging in evals...

by suaveant (Parson)
on May 07, 2008 at 21:09 UTC ( [id://685329]=perlquestion: print w/replies, xml ) Need Help??

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

Some time ago I wrote a module for our code that tied STDERR and wrote all STDERR to error logs with timestamps. It works pretty well but I just came across a slight annoying flaw; sometimes it works too well.

When an there is an error in an eval, like: $a=10; eval {$a->isa('foo')}; I actually get the error message printed to my error log, even though Perl normally wouldn't print such a message, only store it in $@.

Is there some easy way to catch the fact I'm in an eval so I can suppress writing the message to the error file?

                - Ant
                - Some of my best work - (1 2 3)

Replies are listed 'Best First'.
Re: Prevent my STDERR logging in evals...
by moritz (Cardinal) on May 07, 2008 at 21:33 UTC
    I can't reproduce that behaviour with a simple tied filehandle:
    #!/usr/bin/perl use strict; use warnings; my $i = 10; sub TIEHANDLE { return bless {}, 'main'; } sub PRINT { my ($self, $str) = @_; print STDOUT "in PRINT: <<$str>>\n"; } tie *STDERR, 'main'; warn "foo"; eval { $i->foo(); }; __END__ in PRINT: <<foo at test.pl line 18. >>

    In this case the error from within the eval doesn't get forwarded to PRINT.

    Could you please provide an example that we can use to reproduce your error?

Re: Prevent my STDERR logging in evals...
by ikegami (Patriarch) on May 07, 2008 at 22:27 UTC

    That doesn't make sense. Exceptions such as the one you provided are caught by eval and don't print anything.

    >perl -we"$a=10; $a->isa('foo');" Can't call method "isa" without a package or object reference at -e li +ne 1. >perl -we"eval { $a=10; $a->isa('foo'); }" >

    So you either used a bad example or you have a buggy __DIE__ handler. (It should check $^S.)

    Assuming you just picked a bad example, eval doesn't affect warnings, which can be avoided with writing a warning handler

    >perl -we"eval { $a='abc'; $a += 5; } Argument "abc" isn't numeric in addition (+) at -e line 1. >perl -we"eval { local $SIG{__WARN__} = sub {}; $a='abc'; $a += 5 }" >

    Of course, that neither eval nor a warning handler prevents from writing to STDERR in general. local *STDERR; will handle most cases. The exception would be if you spawned a child process.

    >perl -we"eval { print STDERR qq{foo\n}; }" Argument "abc" isn't numeric in addition (+) at -e line 1. >perl -we"eval { local *STDERR; print STDERR qq{foo\n}; }" print() on unopened filehandle STDERR at -e line 1. >perl -we"eval { local $SIG{__WARN__} = sub {}; local *STDERR; print S +TDERR qq{foo\n}; }" print() on unopened filehandle STDERR at -e line 1. >

    By the way, you can avoid the need for any of shenanigans in this particular case by using isa as a function.

    >perl -we"$a=10; UNIVERSAL::isa($a, 'foo');" >
      By the way, you can avoid the need for any of shenanigans in this particular case by using isa as a function.

      ... in the same way that you can avoid warnings by not using strict and warnings and redirecting STDERR to /dev/null.

        No, turning off warnings will not turn them off in called functions and won't mute explicit calls to warn.

        Yes, redirecting STDERR is another option (although /dev doesn't exist on my system).

        >perl -we"eval { local *STDERR; open(STDERR, '>', 'NUL'); print STDERR + qq{foo\n}; }" >
Re: Prevent my STDERR logging in evals...
by Old_Gray_Bear (Bishop) on May 07, 2008 at 22:59 UTC
    Ant said: "Is there some easy way to catch the fact I'm in an eval so I can suppress writing the message to the error file?"

    I seem to remember that  caller(0) can give you that information. You have to specify the call-frame explicitly to get the full spectrum of data. The fourth element of the array is 'subroutine name', if you are in an eval block it reads '(eval)'.

    ----
    I Go Back to Sleep, Now.

    OGB

      $^S is an easier way to check if you're in an eval.
Re: Prevent my STDERR logging in evals...
by mscharrer (Hermit) on May 07, 2008 at 21:25 UTC
    Just a guess: Did you tried to set $SIG{__WARN__} to an empty sub { } or to undef at the very beginning of the eval to catch the warnings?

    Update: I thought now about a tiny test for this:
    perl -e '$a=10; eval { $SIG{__WARN__} = sub {  }; $a->isa('foo')}; print "Eval: ", $@, "\n"'
    or
    perl -e '$a=10; eval { $SIG{__WARN__} = undef; $a->isa('foo')}; print "Eval: ", $@, "\n"'

    Both have the warning still in $@. I can't say much about a tied STDERR but it looks pretty much that this isn't working. One another idea I had was to localise the STDERR typeglob inside eval:

    perl -e '$a=10; eval { local *STDERR; print STDERR "Test\n"; $a->isa('foo'); }; print $@;'

    While this still sets the warning inside $@ the message to STDERR isn't printed. It's worth a try.

      Close, but so wrong!
      • $SIG{__WARN__} should have been localized.
      • $SIG{__WARN__} doesn't hide the message from an exception such as $a=10; $a->isa('foo').
      • local *STDERR; simply replaces the text with the warning "print() on unopened filehandle STDERR".
      • Warnings don't set $@.
      Aha! Yes, I did redefine the sig handlers for warn and die and that is the problem. I'm not even sure why I did it any more this was written so long ago.

      Silly me... thanks!

                      - Ant
                      - Some of my best work - (1 2 3)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://685329]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (1)
As of 2024-04-18 23:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found