Reputation: 40299
How can I print to a variable with Perl?
I've been working on a program for a while which logs its iterative progress in a highly verbose fashion...
print $loghandle $some_message;
However, I'd like to also selectively print some of the messages to a different file. Naturally, I could sprinkle the code with...
print $loghandle $some_message
print $otherloghandle $some_message
Or rewrite the whole business into a function. Blah.
What I want to do is do some magic when I open the $loghandle so that when I'm print
'ing, I'm actually just doing a sprintf
ish operation against a variable(call it $current_iteration
), so that when I get down to a decision point I can do something like this...
print $real_log_file $current_iteration;
print $other_real_log_file $current_iteration if($condition);
I'm fairly sure I've seen something like this somewhere, but I have no idea where it is or where to look.
edit: File::Tee solves this problem to some extent on *nix, but I run on Windows.
Upvotes: 11
Views: 10724
Reputation: 40299
This is a tremendous hack, and I think mobrule's solution or(esp) Sinan's solution of Log4Perl are the way to go when I have time.
But, this is what I'm using, as a completion thing:
sub print_to_var($$) {
my($rx_var, $scalar) = @_;
$$rx_var .= $scalar;
}
print_to_var \$logvar, $message;
#...later on...
print $somefile $logvar;
Edit:
Since this is community wiki, it's worth nothing that Perl aliases arguments to functions. That means you can just write this:
sub print_to_var($$) {
$_[0] .= $_[1];
}
And then say:
my $foo = "OH HAI. ";
print_to_var $foo, "I ARE HELO KITTIE.";
say $foo; # OH HAI. I ARE HELO KITTIE.
This is not a particularly tremendous hack, although print_to_var
is a lot more typing than .
is.
And here is the HELO KITTIE:
helo kittie http://blogs.philadelphiaweekly.com/style/files/2008/11/hello-kitty-color.gif
Upvotes: 1
Reputation: 132758
If you want to do selective logging where you can control which messages are logged and where they are logged, use Log::Log4perl. That will save you a bunch of time over messing with tie
s and other black magic.
Upvotes: 4
Reputation: 53966
You can treat a scalar variable as a filehandle by open
ing it:
open my $fh, '>', \$variable or die "Can't open variable: $!";
print $fh "Treat this filehandle like any other\n";
You can even map stdout or stderr to a scalar:
close STDOUT;
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";
If you want to split your output or set up a config file to do "interesting" things with your logging, you are better off with Log4Perl as others have suggested.
Upvotes: 21
Reputation: 5164
Do you mean something like IO::Scalar? Lets you write to a variable with filehandle semantics.
Upvotes: 5
Reputation: 27173
Perlfaq5 recommends Tie::FileHandle::Multiplex for printing to multiple files.
The source is very simple and it should be easy to modify with a per-handle filter.
Upvotes: 2
Reputation: 118595
Sound like you want to tie
your filehandle.
my $x;
# printing to $fh will update the variable $x
# when you close $fh, it will print $x to a filehandle depending
# on code in the function Print_to_variable::CLOSE
tie $fh, "Print_to_variable", \$x, $output_fh1, $output_fh2;
print $fh "stuff";
print $fh "more stuff";
close $fh;
sub Print_to_variable::TIEHANDLE {
my ($class, $ref, $fh1, $fh2) = @_;
my $self = {};
$self->{ref} = $ref;
$self->{output_fh1} = $fh1;
$self->{output_fh2} = $fh2;
bless $self, "Print_to_variable";
$self;
}
sub Print_to_variable::PRINT {
my ($self,@list);
${$self->{ref}} .= join "", @list;
}
sub Print_to_variable::CLOSE {
my $self = shift;
my $text = ${$self->{ref}};
if ( &myCondition1($text) ) { # ... how you decide where to print
print {$self->{output_fh1}} $text;
} else {
print {$self->{output_fh1}} $text;
}
}
Upvotes: 1
Reputation: 66947
You can use File::Tee to split a filehandle into multiple output streams.
use File::Tee;
open my $fh, '>', 'logfile.txt' or die $!;
tee( $fh, '>', 'otherlogfile.txt' ) if $condition;
print $fh $current_iteration; # will also go to otherlogfile.txt
# if $condition was true
Upvotes: 2