tags:

views:

322

answers:

5

I would like to copy stdout and stderr of my Perl script to a file, while retaining it also onscreen, and preferrably using some trick inside the script itself. I.e. I want something similar to

./test.pl 2>&1 | tee foo.bar

but hidden inside the perl script implementation. For the moment I've just written a subroutine which prints all messages both onscreen and to a filehandle, but the drawback is that if the script dies, the die message will not appear in the log. Is there a way to do it?

A: 

This sounds like just what you need, unfortunately it's a bash script and you would like this all to be handled in your perl code.

nullpointer
mobrule
+1  A: 

Take a look at Log::Dispatch
Dispatches messages to one or more outputs.

   use Log::Dispatch;

   # Simple API
   #
   my $log =
       Log::Dispatch->new
           ( outputs =>
                 [ [ 'File',   min_level => 'debug', filename => 'logfile' ],
                   [ 'Screen', min_level => 'warning' ],
                 ],
           );

   $log->info('Blah, blah');

   # More verbose API
   #
   my $log = Log::Dispatch->new();
   $log->add( Log::Dispatch::File->new
                         ( name      => 'file1',
                           min_level => 'debug',
                           filename  => 'logfile'
                         )
                   );
   $log->add( Log::Dispatch::Screen->new
                         ( name      => 'screen',
                           min_level => 'warning',
                         )
                   );

   $log->log( level => 'info', message => 'Blah, blah' );

   my $sub = sub { my %p = @_; return reverse $p{message}; };
   my $reversing_dispatcher = Log::Dispatch->new( callbacks => $sub );

It has a few helper/utility modules you should look at too.

Log::Dispatch::DBI - Log output to a database table.

Log::Dispatch::FileRotate - Rotates log files periodically as part of its usage.

Log::Dispatch::File::Stamped - Stamps log files with date and time information.

Log::Dispatch::Jabber - Logs messages via Jabber.

Log::Dispatch::Tk - Logs messages to a Tk window.

Log::Dispatch::Win32EventLog - Logs messages to the Windows event log.

Log::Dispatch::Config - Allows configuration of logging via a text file similar (or so I'm told) to how it is done with log4j.

Nifle
+5  A: 

Please see section "13.15.9. Tie Example: Multiple Sink Filehandles" in Perl cookbook

The main thing to know is tie *TEE, "Tie::Tee", @handles;

NOTE: Tie::Tee package is something you need to create yourself, the code is in that same section in the book.

NOTE: you can then do select(TEE) and it will be used in every regular print statement, so you don't need to do print TEE xxx.

NOTE: To have any STDERRy output (including die) go to the same filehandle, change the STDERR to TEE like this:

use Tie::Tee; 
use Symbol; 
@handles = (*STDOUT); 
push(@handles, $handle = gensym( )); 
open($handle, ">/tmp/teetest.xxx"); 
tie *TEE, "Tie::Tee", @handles; 
select(TEE); 
*STDERR = *TEE; 
print "raw print\n"; 
die "XXXX\n";

The output will be:

raw print
XXXX

And the file contents will be:

raw print
XXXX
DVK
That perl cookbook link is to a pirate copy. You can link into google books for a legal link. Rampant piracy of the CD bookshelf series killed it, and now I can't buy new ones.
daotoad
@daotoad - sorry, didn't grok that. I just picked the first link off of Google search. Feel free to edit with the correct link - I will try to edit as soon as I have time to search for Google Books one if you haven't added on by then
DVK
@DVK: No, that's not really a reasonable response. If you know the link is to a pirated copy of a book, please remove that link immediately. If you (or someone else) finds a legal link, great - you can post it later. But remove the pirated copy.
Telemachus
No, it was an un-reasonable request. It is a Wiki - instead of complaining about something, people should just fix it (like you did). I'm at work now and don't have time to do detailed searches to find The One Correct Electonic Copy - if the guy cared so much, he should have simply done it himself.
DVK
I fixed a link - the answer was fond in 3 mins of Googling. Wasn't so hard was it?
DVK
Thanks a lot, this one seems to be closest to what I was looking for!
azerole
A: 

Capture::Tiny features a tee sub.

Geo
A: 

Depending on the size of your script, I highly recommend Log::Log4perl ... saves reimplementing logging every time you write a script.

If you use Log4perl in easy mode, it only adds about 10 lines or so of code and is very useful.

Log4perl is extremely flexible in redirecting output to almost anywhere you want, including multiple outputs at once.

James