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

Hello, guys!

I use some XS library, that writes to stderr itself log by the libc fprintf() function. In perl script I wanna catch all stderr, produced by this library, but I couldn't, due to stdio makes output buffered.

Code like:

select(STDERR); $| = 1;
did not help, because XS and perl code have the same file descriptor (2), but the different bound stdio buffers.

The only thing, that helped me, is flushing of all open output streams:

use Inline C => <<'END_C'; void make_flush() { fflush(NULL); } END_C
Please, can anyone help me to make this flush without using of C inlined code?

Replies are listed 'Best First'.
Re: Flush all opened STDIO streams
by Anonymous Monk on Feb 03, 2014 at 12:57 UTC

      List, what I tried to use:

      1. Reopen STDERR to variable;

      2. Reopen STDERR to file;

      3. Capture::Tiny and some others (sorry do not understand already);

      4. Make hook on $SIG{__WARN__}

      5. Use eval {}

      I figured out slowest and ugly solution: write my perl code to an individual script, and system() or `backtick` it with grabbing stderr.

Re: Flush all opened STDIO streams
by Anonymous Monk on Feb 03, 2014 at 13:01 UTC
      Sorry, but it did not work. Also, I tried:
      STDERR->autoflush(1)
      Another thing, that works is to recompile XS with fflush after logging:
      fprintf(stderr, "..."); fflush(stderr);
      but I can't install/update XS package on the production servers. May be anyone knows some perl module, that can do fflush(NULL)?

        What is the fileno of that c/xs stderr versus perl's STDERR?

        Maybe you can fake it

        sub flushall { for my $fileno (0..1024){ ## blah blah constants open my($fake), "<&=$fileno"; ## UGLY $fake->flush; } }

        Maybe you can fake it

        sub flushall { use POSIX(); for my $fileno (0.. POSIX::dup( fileno( STDERR) ) ){ open my($fake), ">&=$fileno"; ## UGLY $fake->flush; } }
Re: Flush all opened STDIO streams
by oiskuu (Hermit) on Feb 03, 2014 at 16:57 UTC

      Take a look at perlapio.

      Why?

Re: Flush all opened STDIO streams
by dmitnin (Initiate) on Feb 04, 2014 at 12:12 UTC
    The code:
    use Inline C => <<'END_C'; void print_2() { fprintf(stdout, "2\n"); } END_C print STDOUT "1"; print_2(); print STDOUT "\n";

    prints:

    2 1

    It says, that perl has its own system of stream buffering.