Printing to screen and to file

P

Peter Jamieson

I can print to a file by using:

open(STDOUT, ">>tmp.txt");

and print warnings to a file

open(STDERR, ">>tmp.txt");

But what I would like to do is both print STDOUT and STDERR to a file
but also to still view both on screen.

I looked in perldoc and elsewhere but could not see how to do this.
Any help appreciated!
 
P

Paul Lalli

I can print to a file by using:

open(STDOUT, ">>tmp.txt");

and print warnings to a file

open(STDERR, ">>tmp.txt");

But what I would like to do is both print STDOUT and STDERR to a file
but also to still view both on screen.

I looked in perldoc and elsewhere but could not see how to do this.
Any help appreciated!

Use the IO::Tee module from CPAN to create a filehandle that prints to
both the file and STDOUT, select() that filehandle, and then setup a
warn handler to print to the default filehandle rather than STDERR:

$ perl -MIO::Tee -le'
open my $fh, ">", "log.txt" or die $!;
my $tee = IO::Tee->new(\*STDOUT, $fh);
select $tee;
$SIG{__WARN__} = sub { print @_ };
print "Info";
warn "Warning";
'
Info
Warning at -e line 7.

$ cat log.txt
Info
Warning at -e line 7.



Hope this helps,
Paul Lalli
 
P

Peter Jamieson

Hi Paul, Thanks for your assistance!
I have been absent from home for some time and am only now catching up
on things.
I will try your advice asap.
Thanks again, Cheers, Peter

I can print to a file by using:

open(STDOUT, ">>tmp.txt");

and print warnings to a file

open(STDERR, ">>tmp.txt");

But what I would like to do is both print STDOUT and STDERR to a file
but also to still view both on screen.

I looked in perldoc and elsewhere but could not see how to do this.
Any help appreciated!

Use the IO::Tee module from CPAN to create a filehandle that prints to
both the file and STDOUT, select() that filehandle, and then setup a
warn handler to print to the default filehandle rather than STDERR:

$ perl -MIO::Tee -le'
open my $fh, ">", "log.txt" or die $!;
my $tee = IO::Tee->new(\*STDOUT, $fh);
select $tee;
$SIG{__WARN__} = sub { print @_ };
print "Info";
warn "Warning";
'
Info
Warning at -e line 7.

$ cat log.txt
Info
Warning at -e line 7.



Hope this helps,
Paul Lalli
 
P

Peter Jamieson

Hi David, Thanks for your detailed response!
I have been absent from home for some time and am only now catching up
on things.
I will try out code soon.
Thank you!, Cheers, Peter


David Filmer said:
Peter said:
But what I would like to do is both print STDOUT and STDERR to a file
but also to still view both on screen.

If you want to get really fancy and versatile you can do this with a
logging module.

My favorite is Log::Dispatch. Here is some sample code that I use in my
"skeleton" boilerplate starter script to do all the work of setting up
the logging methods (you need to do a bunch of stuff up-front, but once
it's done, the actual logging is VERY simple, as you will see):

######################################################################
### LOGGING. Levels are: #############################################
### debug info notice warning error critical alert emergency ##
######################################################################
##
use Mail::Sendmail; ##
use Log::Dispatch; ##
use Log::Dispatch::Screen; ##
use Log::Dispatch::File; ##
use Log::Dispatch::Email::MailSendmail; ##
##
my $log; ##
##
LOG_METHODS: { #lexically isolate variables in a block ##
my $logdir = $cfg{'dir'}{'log'} || "/var/tmp"; ##
my @admin_email = @{$cfg{'email'}{'admin'}} || ##
sprintf('%s@%s', scalar getpwuid($<), hostname); ##
##
unshift @{$Mail::Sendmail::mailcfg{'smtp'}}, ##
$cfg{'email'}{'smtp'} || 'localhost'; ##
##
my $add_lf = sub { my %p = @_; "$p{'message'}\n"}; ##
my $add_indent = sub {my %p = @_; " $p{'message'}"}; #for Outlook ##
my $add_timestamp = sub { my %p = @_; ##
sprintf "%s - %s", scalar(localtime), ##
$p{'message'}; }; ##
my $add_level = sub { my %p = @_; ##
sprintf "%-10s %s", ($p{'level'} =~ /debug/i) ##
? lc $p{'level'} ##
: uc $p{'level'},##
$p{'message'} }; ##
##
$log = Log::Dispatch->new ( callbacks => [$add_level, $add_lf] ); ##
##
$log ->add( Log::Dispatch::Screen ->new( ##
name => 'screen', ##
min_level => 'debug', ##
stderr => 0, ) ##
); ##
$log ->add( Log::Dispatch::File ->new( ##
name => 'file', ##
min_level => 'info', ##
filename => sprintf ( "%s/%s.log", ##
$logdir, ##
$FindBin::Script ), ##
mode => 'append', ##
callbacks => $add_timestamp, ##
)); ##
$log ->add( Log::Dispatch::Email::MailSendmail ->new( ##
name => 'email', ##
min_level => 'error', ##
to => \@admin_email, ##
subject => "ERROR in $PROGRAM_NAME", ##
callbacks => $add_indent, ##
from => sprintf ("SERVER<%s\@%s>", ##
(hostname =~ /^([^\.]*)/)[0], ##
'do-not-reply.com' ) , ##
smtp => $cfg{'email'}{'smtp'} || 'localhost', ##
)); ##
}; #do ##

#dispatch our very first message - print all the runtime info ##
$log -> debug(sprintf ##
"[%s] Begin %s\n\tVersion %s on %s as %s\n" ##
."\tConfigFile: %s\n\tKillfile(s):\n%s", ##
__LINE__, __FILE__, ##
$main::VERSION, ##
hostname(), ##
"$REAL_USER_ID ($ENV{'USER'})", ##
$cfg{'inifile'}, ##
map {"\t\t$_\n"} keys %{$cfg{'killfile'}}, ##
); ##
######################################################################

(I'm using a configuration hash (%cfg) which is populated earlier, and
I'm allowing for numerous default values within my method definitions)

This creates three different types of logging methods (console, file,
and e-mail). When we pass a message to the logger, it will fire ANY and
ALL methods which are at (or above) the log level specified for the
various methods. For example,

$log -> debug("This message goes to the screen only");
$log -> info("This message goes to BOTH screen and file.");
$log -> error("This goes to screen, file, AND e-mail");

I could add many other methods as well (database logging, multiple
levels of file logging, etc).

As you can see, I've added several callback functions to do things like
add a timestamp and automatically add linefeeds. I've found that
Outlook can do some funny things with wrapping, so I add an indention
to e-mail messages to avoid Outlook reformatting.

Check it out; it's an amazing module:

http://search.cpan.org/~drolsky/Log-Dispatch-2.11/lib/Log/Dispatch.pm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top