http://www.perlmonks.org?node_id=329745

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

Is is possible to redirect STDERR to a subroutine? The subroutine would then determine what action to take (print, write to file, die, etc) Any ideas?

Replies are listed 'Best First'.
Re: How do I redirect STDERR to a subroutine?
by stvn (Monsignor) on Feb 17, 2004 at 21:49 UTC

    If you really want to redirect *STDERR, then tieing is probably the way to go. But it seems to me (from what i can gather from your very short post) that maybe you really just want to catch all warnings that are generated by perl and act upon their contents. Maybe I am wrong, but if not then I think you might actually be looking for $SIG{__WARN__} instead. See the warn perl doc page for more info.

    - stvn
Re: How do I redirect STDERR to a subroutine?
by BUU (Prior) on Feb 17, 2004 at 21:30 UTC
    tie *STDERR,'MyRandomPackageName'; package MyRandomPackageName; sub TIEHANDLE { bless {}; } sub PRINT { CORE::print(@_); } sub PRINTF{ CORE::print(sprintf@_); } #etc

      Errmm... I tried running that and it went into an infinite loop.... I haven't tried a debugger yet, but...


      Peter L. Berghold -- Unix Professional
      Peter at Berghold dot Net
         Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
Re: How do I redirect STDERR to a subroutine?
by gmpassos (Priest) on Feb 18, 2004 at 05:00 UTC
    Well, for Safe::World I made a full redirection of STDOUT and STDERR, with the option to redirecto to another HANDLER, SUB or SCALAR.

    I have striped this code from it:

    ## Redirecting to another IO: tie(*STDERR => 'Safe::World::stderr' , \*STDOUT ) ; ## Redirecting to a SUB: sub errors { print "ERR>> @_\n" ;} tie(*STDERR => 'Safe::World::stderr' , \&errors ) ; ## Redirecting to a scalar: my $stderr ; tie(*STDERR => 'Safe::World::stderr' , \$stderr ) ; print "REDIRECT << $stderr >>\n" ; package Safe::World::stderr ; sub print_stderr { my $this = shift ; my $stderr = $this->{STDERR} ; if ( ref($stderr) eq 'SCALAR' ) { $$stderr .= $_[0] ;} elsif ( ref($stderr) eq 'CODE' ) { &$stderr($_[0]) ;} else { print $stderr $_[0] ;} return 1 ; } sub TIEHANDLE { my $class = shift ; bless( { STDERR => $_[0] } , $class) ; } sub PRINT { my $this = shift ; $this->print_stderr( join("", (@_[0..$#_])) ) ; return 1 ; } sub PRINTF { &PRINT($_[0],sprintf($_[1],@_[2..$#_])) ;} sub READ {} sub READLINE {} sub GETC {} sub WRITE {} sub FILENO {} sub CLOSE {} sub DESTROY {}
    Note that if you want to catch all the error messages, you also should set $SIG{__WARN__} and $SIG{__DIE__}:
    $SIG{__WARN__} = \&print_stderr ; $SIG{__DIE__} = \&handle_die ;

    Enjoy! ;-P

    Graciliano M. P.
    "Creativity is the expression of the liberty".

      That's interesting code; I really liked this bit in the PRINT sub :) @_[0..$#_] A bit of unnecessary redundancy?

      Thanks very much for this.

      Filter::Handle didn't work for me when trying to divert stderr to a subroutine (it went into an infinite loop), but your code works perfectly.

      mde, London, England

Re: How do I redirect STDERR to a subroutine?
by RhetTbull (Curate) on Feb 18, 2004 at 01:55 UTC
    I usually use Filter::Handle for this sort of thing. There's a code snippet that shows how to do this here.
Re: How do I redirect STDERR to a subroutine?
by samtregar (Abbot) on Feb 17, 2004 at 22:33 UTC
    Why do you want to do this? I suspect there may be an easier way to meet your needs. Messing with the standard streams should be your last resort.

    -sam

      You can use the open in conjuction with STDOUT and STDERR redirections, or test the @_ resulting from the eval function ... Brett
      http://www.brettsbsd.net
      You've said: "Messing with the standard streams should be your last resort."

      I've had a a question about STDERR not long ago, so I'm curious: could you explain why it should be the last resort?

      For an example, if my perl program runs in a Win32 environment without a DOS box, unless I "mess" with STDERR and put it into a file, I'd never see any errors generated by perl... So, you can say messing with STDERR was my first resort ;)

      Thanks,

      my ($author_nickname, $author_email) = ("DaWolf","erabbott\@terra.com.br") if ($author_name eq "Er Galvão Abbott");
        TMTOWTDI ... and ... Good advice is not always cross-platform. :)
        I don't know much about Win32, but it sounds like STDERR is broken there. On Linux STDERR is virtually never broken unless you break it yourself. And if you do, there'll be hell to pay. Not too long ago I helped a co-worker track down a very difficult bug; in the end it turned out that he'd effectively closed STDERR and wasn't seeing the simple error message that would have helped him find the problem.

        -sam

Re: How do I redirect STDERR to a subroutine?
by Anonymous Monk on Feb 17, 2004 at 22:09 UTC
    perldoc perltie
    perldoc IO::Handle