Re: Print to several logs
There are some good answers here so far, but I'd like to recommend a logging module like Log::Log4perl. If your script is more than a run-once throwaway, proper logging will almost certainly be of benefit. Metacpan: https://metacpan.org/module/Log::Log4perl FAQ: http://log4perl.sourceforge.net/releases/Log-Log4perl/docs/html/Log/Log4perl/FAQ.html Tutorial: http://www.perl.com/pub/2002/09/11/log4perl.html To log to two files: #!/usr/bin/perl use strict; use warnings; use Log::Log4perl qw(get_logger); # Normally this would be in a separate file my $log4perl_cfg = 'EOCFG'; # Two appenders in our logger tmplog1 tmplog2 log4perl.logger = DEBUG, tmplog1, tmplog2 log4perl.appender.tmplog1 = Log::Log4perl::Appender::File log4perl.appender.tmplog1.filename = /var/tmp/one.log log4perl.appender.tmplog1.layout = PatternLayout log4perl.appender.tmplog1.layout.ConversionPattern = %d %m%n log4perl.appender.tmplog2 = Log::Log4perl::Appender::File log4perl.appender.tmplog2.filename = /var/tmp/two.log log4perl.appender.tmplog2.layout = PatternLayout log4perl.appender.tmplog2.layout.ConversionPattern = %d %m%n EOCFG Log::Log4perl-init( \$log4perl_cfg ); my $logger = get_logger(); my $rsync = 'rsync'; $logger-debug('About to rsync'); ...; $logger-info(kdkdkdkd Output from: $rsync cmdflgs); exit 0; Using Log4perl allows you to change how you log very easily, with appenders for output to files, the screen, databases etc. all available. The configuration format is somewhat verbose, so I generally use the Template Toolkit to generate it for me. The example below solves your same problem, but for N files instead of two: #!/usr/bin/perl use strict; use warnings; use Log::Log4perl qw(get_logger); use Template; my $logging_cfg_template = 'EOCFG'; [% BLOCK appenders -%] [% FOR section IN sections %][% section.log_appender_name %][% , UNLESS loop.last %][% END %] [%- END %] [% BLOCK appender_sections %] [% FOR section IN sections %] log4perl.appender.[% section.log_appender_name %] = Log::Log4perl::Appender::File log4perl.appender.[% section.log_appender_name %].filename = [% section.log_file_name %] log4perl.appender.[% section.log_appender_name %].layout = PatternLayout log4perl.appender.[% section.log_appender_name %].layout.ConversionPattern = %d %m%n [% END %] [% END %] log4perl.logger = DEBUG, [% PROCESS appenders %] [% PROCESS appender_sections %] EOCFG my $template = { sections = [ { log_appender_name = 'tmplog1', log_file_name = '/var/log/one.log', }, { log_appender_name = 'tmplog2', log_file_name = '/var/log/two.log', }, { log_appender_name = 'tmplog3', log_file_name = '/var/log/three.log', }, ], }; my $tt = Template-new(); my $log4perl_cfg; $tt-process( \$logging_cfg_template, $template, \$log4perl_cfg ) || die 'Template error: ' . $tt-error(); # Comment or remove this line once you are happy with the generated config print CONFIG: $log4perl_cfg\n; Log::Log4perl-init( \$log4perl_cfg ); my $logger = get_logger('main'); my $rsync = 'rsync'; $logger-info(kdkdkdkd Output from: $rsync cmdflgs); Cheers, Michael On 08/28/2013 06:44 AM, Harry Putnam wrote: I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? I tried just adding the second one to the first print like this: print LOG LOG2 [...]; But that fails with an error: String found where operator expected at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs (Do you need to predeclare LOG2?) syntax error at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs Execution of ./t1.pl aborted due to compilation errors. -- Michael BraderSenior Software Engineer and Perl Person Our World Wide Web has a World Wide Network Technology/Softdev/DevOps Internode http://internode.on.net/ mbra...@internode.com.au iiNet http://iinet.net.au/ m.bra...@staff.iinet.net.au -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
Rob Dixon rob.di...@gmx.com writes: On 27/08/2013 23:06, John W. Krahn wrote: Harry Putnam wrote: [...] (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? my %logs = ( 'one.log' = undef, 'two.log' = undef, ); for my $name ( keys %logs ) { open my $FH, '', $name or die Cannot open '$name' because: $!; $logs{ $name } = $FH; } for my $log_FH ( values %logs ) { print $log_FH kdkdkdkd Output from:\n$rsync cmdflgs; } Nice John Yes very nice... thank you John It compacts neatly to [...] snipped neatly compacted code Nicely compacted... thank you Rob. Thanks to all other posters.. lots of good input. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On Wed, 28 Aug 2013 10:42:30 -0400 Harry Putnam rea...@newsguy.com wrote: Thanks to all other posters.. lots of good input. It seems to me that recording the same information is many places is a design flaw. If you have the same information in two or more places, it will get out of sync. Write the program that will detect and correct this, now, not later. -- Don't stop where the ink does. Shawn -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
Shawn H Corey shawnhco...@gmail.com writes: On Wed, 28 Aug 2013 10:42:30 -0400 Harry Putnam rea...@newsguy.com wrote: Thanks to all other posters.. lots of good input. It seems to me that recording the same information is many places is a design flaw. If you have the same information in two or more places, it will get out of sync. Write the program that will detect and correct this, now, not later. Good thinking thanks. It might not really apply here though. I'm no kind of data manager... just a homeboy hillbilly. What I had in mind is writing to a single log file that is dated on the file name for each run of the program. That file will sooner or later be deleted by another part of the script that will try to leave 5 of the most recent logs. I was going to just cat the fresh log, onto an accumlative log after each run so the info would stick around for a while longer in case some kind of problem came up requiring research into previous runs older than the 5 dated logs. So the info is really only duplicated for a few weeks. That accumulative file might grow quite a bit. I find it handier to look thru a few dated logs that are much smaller ... but if it comes down to it and the dated logs don't go back far enough then I can find it in the accumulative log. That too, will get trimmed back eventually, That sounds quite a bit like what cron could do with this hmm. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On Wed, 28 Aug 2013 12:34:40 -0400 Harry Putnam rea...@newsguy.com wrote: That sounds quite a bit like what cron could do with this hmm. Or use a hard link to preserve the file. -- Don't stop where the ink does. Shawn -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
Rob Dixon wrote: On 27/08/2013 23:06, John W. Krahn wrote: my %logs = ( 'one.log' = undef, 'two.log' = undef, ); for my $name ( keys %logs ) { open my $FH, '', $name or die Cannot open '$name' because: $!; $logs{ $name } = $FH; } for my $log_FH ( values %logs ) { print $log_FH kdkdkdkd Output from:\n$rsync cmdflgs; } Nice John It compacts neatly to use strict; use warnings; use autodie; my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; my %logs = map { open my $FH, '', $_; What if open fails?! ($_ = $FH); } $tmplog, $tmplog2; Or a bit more compact: my %logs = map { open my $FH, '', $_ or die Cannot open '$name' because: $!; ( $_ = $FH ); } my ( $tmplog, $tmplog2 ) = qw( one.log two.log ); John -- Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction. -- Albert Einstein -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On 28/08/2013 19:06, John W. Krahn wrote: Rob Dixon wrote: use strict; use warnings; use autodie; my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; my %logs = map { open my $FH, '', $_; What if open fails?! I have `use autodie`. Rob -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On Wed, 28 Aug 2013 12:34:40 -0400 Harry Putnam rea...@newsguy.com wrote: Good thinking thanks. It might not really apply here though. I'm no kind of data manager... just a homeboy hillbilly. What I had in mind is writing to a single log file that is dated on the file name for each run of the program. That file will sooner or later be deleted by another part of the script that will try to leave 5 of the most recent logs. Try this. It will keep rotating log files for the day-of-month, month, and year. # -- # Name: start_logging # Usage: $log_fh = start_logging( $log_file ); #Purpose: To open log file and set a day-of-month, month, and year # file that tracks it. # Parameters: $log_file -- full path to log file #Returns: $log_fh -- file handle to open log file # use Carp; use English qw( -no_match_vars ); # Avoids regex performance penalty use File::Basename; use POSIX; sub start_logging { my $log_file = shift @_; my @now = localtime; open my $log_fh, '', $log_file or croak could not open $log_file because: $OS_ERROR\n; my $dir = dirname( $log_file ); # link to day-of-month log file my $day_file = strftime $dir/day_%d.log, @now; unlink $day_file; # ignore errors link $log_file, $day_file or carp could not link to day-of-month file, $day_file because: $OS_ERROR\n; # link to month log file my $month_file = strftime $dir/mo_%m.log, @now; unlink $month_file; # ignore errors link $log_file, $month_file or carp could not link to day-of-month file, $month_file because: $OS_ERROR\n; # link to year log file my $year_file = strftime $dir/yr_%Y.log, @now; unlink $year_file; # ignore errors link $log_file, $year_file or carp could not link to day-of-month file, $year_file because: $OS_ERROR\n; return $log_fh; } -- Don't stop where the ink does. Shawn -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Print to several logs
I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? I tried just adding the second one to the first print like this: print LOG LOG2 [...]; But that fails with an error: String found where operator expected at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs (Do you need to predeclare LOG2?) syntax error at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs Execution of ./t1.pl aborted due to compilation errors. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
Harry Putnam wrote: I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? my %logs = ( 'one.log' = undef, 'two.log' = undef, ); for my $name ( keys %logs ) { open my $FH, '', $name or die Cannot open '$name' because: $!; $logs{ $name } = $FH; } for my $log_FH ( values %logs ) { print $log_FH kdkdkdkd Output from:\n$rsync cmdflgs; } John -- Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction. -- Albert Einstein -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
See reply below, please I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? I tried just adding the second one to the first print like this: print LOG LOG2 [...]; But that fails with an error: String found where operator expected at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs (Do you need to predeclare LOG2?) syntax error at ./t1.pl line 109, near LOG2 kdkdkdkd Output from:\n$rsync cmdflgs Execution of ./t1.pl aborted due to compilation errors. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/ Harry, In my quest to always attack small rodents with bazookas, I came up with a solution that involves OO. It is a small class file. Yes, to all of the OO lovers out there, I *know* that it is not 100% ready for prime time... it is simply a small example for Harry (or any other interested party) to see. Before using it in production, the error checking needs to be fleshed out/changed, etc., etc. But, flame away if you feel the need. Anyway.. using this little class (I named Multiprint), your code would look something like this: use Multiprint; my $rsync = rsync; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; my $mp = Multiprint-new(); $mp-open(LOG, , $tmplog); $mp-open(LOG2, , $tmplog2); $mp-print(kdkdkdkd Output from:\n$rsync cmdflgs); The opens are not 100% necessary.. the class will accept file specifications in the call to new() also. I omitted the close calls, also, because the module takes care of it for you, but there is a close() method provided. Please see the code for the module below for more information. Best of luck, Harry Nathan Multiprint.pm: package Multiprint; # # Multiprint: Less ugly printing to multiple file handles # # [name, mode, filename] # # new: create a new Multiprint instance. May optionally except one or more ARRAY REFS as # arguments. If provided, the array refs must refer to three element arrays. The first # element is an internal name that is used to access the filehandle, the second element # is a mode (and must be either or , for overwrite and append respectively), and # the third element is the path name of the file to open. Returns a blessed reference to # a Multiprint object. # sub new { my $class = shift; my $self = {}; bless $self, $class; $self-{FILES} = {}; foreach my $filespecref (@_) { $self-open(@$filespecref ) if ref($filespecref) eq 'ARRAY'; } return $self; } # # open: Opens a file for output. Requires three arguments; an internal name, a mode, and # a file path name. See new() for more information. # sub open { my ($self, $name, $mode, $fname) = @_; if (! defined $name or ! defined $fname or ! defined $mode or $mode !~ /\{1,2}/ ) { die Error: arguments to open() were invalid } open my $fh, $mode, $fname or die Error opening file $fname: $!; $self-{FILES}{$name} = [$fh, $fname]; return $fh; } # # print: Accepts one or more arguments. The arguments are printed to all of the open files, # in ASCIIbetical order. # sub print { my $self = shift; foreach my $fileentry (sort keys %{$self-{FILES}}) { my $fh = $self-{FILES}{$fileentry}[0]; print {$fh} @_; } return 1; } # # close: Closes a file. Requires one parameter, the internal name of the file to close. # not technically necessary, because all files would be automatically closed when the # file handle reference is garbage collected, but is nice to have anyway. This sub # is also used by the DESTROY method to close all files explicitly when the object instance is # destroyed # sub close { my $self = shift; my $name = shift; close $self-{FILES}{$name}[0] if exists $self-{FILES}{$name}; return 1; } # # DESTROY: Called automagically when an instance of Multiprint has no more active references. # Simply closes each file. # sub DESTROY { my $self = shift; foreach my $name (sort keys %{$self-{FILES}}) { $self-close($name); } } 1; -- -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On Aug 27, 2013, at 2:14 PM, Harry Putnam wrote: I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (snipped) Check out the IO::Tee module from CPAN. I have not used it, but it is mentioned in several web forums. Search for 'perl print multiple file handles' for links. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
On 27/08/2013 23:06, John W. Krahn wrote: Harry Putnam wrote: I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (Simplified for discussion, from a longer script) my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; open(LOG,$tmplog)or die Can't open $tmplog : $!; open(LOG2,$tmplog2)or die Can't open $tmplog2: $!; print LOG kdkdkdkd Output from:\n$rsync cmdflgs; print LOG2 kdkdkdkd Output from:\n$rsync cmdflgs close(LOG); close(LOG2); Is there some smooth way to write to more than one log? my %logs = ( 'one.log' = undef, 'two.log' = undef, ); for my $name ( keys %logs ) { open my $FH, '', $name or die Cannot open '$name' because: $!; $logs{ $name } = $FH; } for my $log_FH ( values %logs ) { print $log_FH kdkdkdkd Output from:\n$rsync cmdflgs; } Nice John It compacts neatly to use strict; use warnings; use autodie; my $rsync = 'rsync'; my $tmplog = 'one.log'; my $tmplog2 = 'two.log'; my %logs = map { open my $FH, '', $_; ($_ = $FH); } $tmplog, $tmplog2; print $_ kdkdkdkd Output from:\n$rsync cmdflgs\n for values %logs; Rob -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: Print to several logs
Jim, *much* better. I did a search for something like that before I wrote what I did, but I guess I didn't get the search terms right, because I didn't find it. Very cool Nathan On Aug 27, 2013, at 2:14 PM, Harry Putnam wrote: I happen to be scripting something that needs to have two logs written to and was sort of taken by how awkward this construction looked: (snipped) Check out the IO::Tee module from CPAN. I have not used it, but it is mentioned in several web forums. Search for 'perl print multiple file handles' for links. -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/ -- -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/