Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

How to capture child process output and divert to log4perl

by chrestomanci (Priest)
on Sep 14, 2012 at 16:29 UTC ( [id://993754]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings wise brothers.

I am working on a perl program that calls a another executable on my system that I don't control. The second program is rather verbose and emits rather more output than I am not usualy interested in on stderr. I am currently calling it via system $program, @args

Rather than suppress output entirely, I am looking for a way to capture the output and log it via Log::Log4perl, as it may be usefull in future to debug problems. Is there a simple way to do this?

I found this node from 4 years ago, where it appears that the suplicant did control the child process. There is also an FAQ entry which handles the case of a perl module that the users is unwilling to modify by localy replacing print with something that diverts what it receves.

Replies are listed 'Best First'.
Re: How to capture child process output and divert to log4perl
by ww (Archbishop) on Sep 14, 2012 at 18:41 UTC
    Does any of this (truncated) look helpful? relevant?
    C:\>perldoc -q stderr Found in C:\Perl\lib\pods\perlfaq8.pod How can I capture STDERR from an external command? There are three basic ways of running external commands: system $cmd; # using system() $output = `$cmd`; # using backticks (``) open (PIPE, "cmd |"); # using open() With "system()", both STDOUT and STDERR will go the same place as +the script's STDOUT and STDERR, unless the "system()" command redirect +s them. Backticks and "open()" read only the STDOUT of your command. You can also use the "open3()" function from "IPC::Open3". Benjami +n Goldberg provides some sample code: To capture a program's STDOUT, but discard its STDERR: use IPC::Open3; use File::Spec; use Symbol qw(gensym); open(NULL, ">", File::Spec->devnull); my $pid = open3(gensym, \*PH, ">&NULL", "cmd"); while( <PH> ) { } waitpid($pid, 0); To capture a program's STDERR, but discard its STDOUT: use IPC::Open3; use File::Spec; use Symbol qw(gensym); open(NULL, ">", File::Spec->devnull); my $pid = open3(gensym, ">&NULL", \*PH, "cmd"); while( <PH> ) { }
Re: How to capture child process output and divert to log4perl
by kennethk (Abbot) on Sep 14, 2012 at 22:31 UTC
    You could go for IPC::Open3, but I've had mixed results with it (because I'm too clever for my own good). I usually do a full blown pipe, fork and exec -- maybe something like:
    pipe my $cin, my $pin; pipe my $pout, my $cout; pipe my $perr, my $cerr; $pin->autoflush(1); $cout->autoflush(1); $cerr->autoflush(1); my $pid = fork(); warn("Fork failed\n"),return unless defined $pid; if ($pid == 0) { # Child fork/TDE execute close $pin; open STDIN, "<&", $cin or die "Map fail (STDIN): $!, $?\n"; exit 1 if fileno(STDIN) != 0; close $pout; close STDOUT; open STDOUT, ">&", $cout or die "Map fail (STDOUT): $!, $?\n"; exit 1 if fileno(STDOUT) != 1; close $perr; close STDERR; open STDERR, ">&", $cerr or print("Map fail (STDERR): $!, $?\n +"),exit 1; exit 1 if fileno(STDERR) != 2; exec $command; } # Parent fork/tester return 0 if eval { alarm $timeout; local $SIG{ALRM} = sub { kill 9, $pid; die "Calculation call failed to return with $timeout secon +ds\n"; }; close $cin; close $cout; close $cerr; close $pin; local $/; # Slurp my $content = eof $pout ? '' : <$pout>; my $error = eof $perr ? '' : <$perr>; alarm 0; unless ($content =~ /\S/) { if ($error =~ /\S/) { $error =~ s/^/\t/mg; $error =~ s/\s*$/\n/; die "No result returned; STDERR=\n$error"; } else { die "Case Aborted: No result, no error\n"; } } elsif ($error =~ /\S/) { $error =~ s/^/\t/mg; warn "$executable output to STDERR for $case$command\n$err +or"; } }
    where obviously, you'll nee to rework the error handling a little. This will give you complete control over all 3 pipes.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: How to capture child process output and divert to log4perl
by jandrew (Chaplain) on Sep 14, 2012 at 23:41 UTC
Re: How to capture child process output and divert to log4perl
by Anonymous Monk on Sep 14, 2012 at 23:53 UTC

    Hi,

    Could you not just use 2> in the system arglist to redirect the stderr to a file? Or am I, as usual, missing something?

    J.C.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2024-03-29 05:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found