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

Hello World!\n

I have an existing script that's rather large and contains many, many print commands. It's got a Tk GUI, but it logs things in the DOS console window.

Since completing it, I've realised that it would be nice to give the user the opportunity to log everything that's printed to the console window to a file.

I have managed to work out that I can print to the screen and a file by using:

use IO::Tee; my $tee = IO::Tee -> new(">stdout.txt", \*STDOUT); print $tee "Cheese!\n";
So, is there a way that I can call a sub that will turn file logging on and off, or must I find every print statement, and replace it, like this?
my $log = 0; print "Do you want to log to a file?"; my $resp = <STDIN>; if ($resp =~ /^y/i) { $log = IO::Tee -> new(">stdout.txt", \*STDOUT); } ... if $log { print $log "What did I want to say?\n" } else { print "What did I want to say?\n" }
Thanks,
Spike.

NEW UPDATE:

I've now found a much better solution, that doesn't need any fiddling about with changing print commands. Actually, it's so obvious, I don't know how I missed it in the first place!

my $tee; sub log_to_file { my ($on, $logfile) = @_; if ($on) { $tee = IO::Tee->new(">>$logfile", \*STDOUT); select $tee; print "Logging console window to $logfile\n"; } else { print "Console window log OFF.\n"; undef $tee; select STDOUT; close $logfile; } }
OLD UPDATE:

Since reading ccn's response (ccn++), I have come up with the following sub to turn file logging on and off:

sub log_to_file { my $on = $_[0]; if ($on) { Log::Log4perl->easy_init ({ level => $DEBUG, file => 'STDOUT', layout => '%m', }, {level => $DEBUG, file => ">> $console_log", layout => '%m', }); } else { Log::Log4perl->easy_init ({ level => $DEBUG, file => 'STDOUT', layout => '%m', }); } }
Then all I did was to search for all print commands, and replaced them with DEBUG. Really cool, thanks ccn!

The only thing I'm now trying to do is incorporate STDERR into the process, but I've had no success, so far.

Replies are listed 'Best First'.
Re: Redirecting STDOUT to file and screen as an afterthought, on Windows.
by ccn (Vicar) on Nov 03, 2004 at 14:53 UTC

    You can use Log::Log4perl

    use Log::Log4perl qw(:easy); Log::Log4perl->easy_init( { level => $DEBUG, file => 'STDOUT', layout => ' - %m%n',}, { level => $DEBUG, file => ">> $0.log"}); DEBUG "$0 started";
Re: Redirecting STDOUT to file and screen as an afterthought, on Windows.
by hlen (Beadle) on Nov 03, 2004 at 15:35 UTC
    How about:
    if ($resp =~ /^y/i) { $log = IO::Tee -> new(">stdout.txt", \*STDOUT); } else { $log = *STDOUT{IO}; }
    Then just print everything to $log.

    Cheers

Re: Redirecting STDOUT to file and screen as an afterthought, on Windows.
by LanceDeeply (Chaplain) on Nov 03, 2004 at 16:00 UTC
    To log to file without modifing all your existing prints use select to make print automatically go to a filehandle.

    use FileHandle; my $log = 0; print "Do you want to log to a file?"; my $resp = <STDIN>; if ($resp =~ /^y/i) { my $fh = new FileHandle; my $filepath = "c:\\stdout.txt"; $fh->open(">> $filepath") || die "could not open log file $filepat +h"; select $fh; } # # this will go to log file if $resp was y # print "Holla!\n";
    -HTH
Re: Redirecting STDOUT to file and screen as an afterthought, on Windows.
by TedPride (Priest) on Nov 04, 2004 at 07:19 UTC
    Pardon my stupidity, but why can't you just copy your code into a text editor and replace all instances of print with print $tee? It would only take about 10 seconds, though I admit that the above suggested methods are probably more elegant.
      How would you do that if the user turns the log_to_file switch on, does some stuff, then turns the log_to_file switch off?

      You'd have to duplicate every print command, like this:

      if ($tee) { print $tee "What did I want to say?\n" } else { print "What did I want to say?\n" }