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

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

I'm writing a program using the Curses::Application module. One issue I've been noticing is that when a die() occurs and a message is sent to STDERR, I never see it. I'm pretty sure the reason for this is that the message is displayed before my Curses::Application object is destroyed, which restores the terminal to normal line buffering mode. While in curses mode, STDOUT and STDERR don't seem to work properly.

Right now I'm redirecting STDERR to a file, but that seems like a poor solution. Does anyone know of a way to 'store' messages to STDERR, and display them only AFTER the Curses::Application object is destroyed? Or maybe have a function that displays the error message in a dialog before closing down the program?

Thanks!

Replies are listed 'Best First'.
Re: Saving STDERR and displaying it later
by jhourcle (Prior) on Jul 03, 2006 at 18:11 UTC

    CPAN is your friend: IO::Capture::Stderr

    (and if you don't want to use something labeled version 0.05, you can always take a look at how they're doing it)

      Hey, this is exactly what I wanted! I'll have to remember to search CPAN more thoroughly next time. Thanks!
        If you dont want to introduce a dependency on IO::Capture::Stderr, and you only want to capture the STDERR from the die() calls, you could try this

        my @dieings; sub my_die() { # localise capture to just my_die() calls... local $SIG{__DIE__} = sub { push(@dieings, @_); }; die(@_); } #... time passes my_die("now we need to capture"); #... time passes print "now we need to report " . Dumper(\@dieings);

        It may be possible to replace die() with this at compile time, I've never tried the *CORE::GLOBAL trick with die(), only open(). I know there are some perl functions where not even compile-time replacement works, die() might be one of those.

        ...reality must take precedence over public relations, for nature cannot be fooled. - R P Feynmann

Re: Saving STDERR and displaying it later
by ikegami (Patriarch) on Jul 04, 2006 at 01:10 UTC

    eval BLOCK catches die. The following catches warnings and other uses of STDERR:

    use v5.8.0; my $stderr; { open(local *STDERR, '>', \$stderr); warn("foo\n"); # no output } print STDERR ("\$stderr: $stderr"); # $stderr: foo

    Together:

    use v5.8.0; my $stderr; eval { open(local *STDERR, '>', \$stderr); warn("foo\n"); # no output die("bar\n"); # no output }; print STDERR ("\$stderr: $stderr"); # $stderr: foo die($@) if $@; # bar

    In earlier version of Perl, I think you can use IO::Scalar to do:
    tie *STDERR, 'IO::Scalar', \$stderr;

Re: Saving STDERR and displaying it later
by GrandFather (Saint) on Jul 03, 2006 at 18:12 UTC

    Sounds like you are half way to a light weight solution - just dump your log file in whatever fashion you think most appropriate.


    DWIM is Perl's answer to Gödel
Re: Saving STDERR and displaying it later
by Hue-Bond (Priest) on Jul 03, 2006 at 18:12 UTC

    Can't you do:

    { my $old = select STDERR; $|++; select $old; }

    ?

    --
    David Serrano

      Wouldn't that just cause output to STDERR to appear immediately? The problem is, any output to STDERR or STDOUT is lost while in curses mode, and curses mode is only left when my Curses::Application object is destroyed. A solution where output to STDERR is 'held' in the buffer indefinitely until allowed to leave (after the DESTROY method is called on the Curses::Application object) would do the trick.

        Ah, now I get it. I thought you were talking about program dying and you not getting STDERR output because of buffering.

        --
        David Serrano