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

O Monk kith,

A simple question I think, but examples are too big for C.B:

I am trying to modify an OO logging library to use 'format' and 'write' to keep timetamps in one column, and messages in another. I am having trouble figuring out how to name the format and then refer to it successfully. The log file works pretty well in the original form, but after making the changes shown below, I get this error:
syntax error at Logger.pm line 60, near "format $FH "
If I give format/filehandle as just 'FILEHANDLE' instead of '$FH' no text is added to the log file or to stdout, and the driver runs forever, then dies with:
Can't coerce UNKNOWN to string in formline at Logger.pm line 94.
subs with modified code are here:
sub lwrite{ my($self,$msg,$value)=@_; # args == object, message and + optional value my $FH=*{$$self{FILEHANDLE}}; # Make a filehandle string fr +om the blob my $tstamp; format $FH = ^<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $tstamp, $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $msg . # Get the local time into an array my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localti +me(time()); my @wdays = qw(Sun Mon Tue Wed Thu Fri Sat); # Make an array o +f weekday names my $weekday = $wdays[$wday]; # Get today's weekday name $year = $year + 1900; # Calculate the current year $mon = $mon + 1; # Calculate the current month # Now format the message with a time stamp in front of the message $tstamp = sprintf("[$weekday %4d-%02d-%02d %02d:%02d:%02d]", $year +, $mon, $mday, $hour, $min, $sec); if(! write $FH ){ # Log it if we cannot print to the file $self->log("Unable to write to $$self{LOG}: $!\n"); } print "\n$msg \n" if ($value ==1); # Print to monitor as w +ell if value == 1 } sub log{ my ($self,$error,$value)=@_; # Args == object, error messag +e and value $self->clear; # Clear last error from the object $$self{ERROR}=$error; # Add the error message to the ob +ject push @{$$self{HISTORY}},$error; # Push the error into the h +istory array carp "$error\n" if $$self{CARP}; # Carp if an error with th +is object $self->lwrite($error,$value); # Send the message and value +to "lwrite" sub above }
Original code is here:
###################################################################### +########## # NAME: Logger # PURPOSE: Single interface for log output # AUTHOR: Marty Gipson, Larry Stone # VERSION: 2006.03.07 11:00 ###################################################################### +########## package Logger; use strict; use Carp; use FileHandle; use Time::HiRes qw/usleep/; use vars qw /$VERSION $SEM $ms/; # Logger is intended to be a single interface for all logging action. +Each instance of Logger is intended to be an output for a particular +type of log; # Logger will save a txt file under c:\\Qagentlogs on windows side and + /root/Qagentlogs on linux # When calling logger, the user should pass filename , message and '1' + to print output to screen. sub new{ my($class,%args)=@_; my $self = bless{ LOG => "c:\\ShopTestHarnessLogs\\$args{LOG}" || croak "No l +ogfile!\n", # Need a name for the logfile or croak CARP => $args{CARP} || undef, FILEHANDLE => new FileHandle || croak "Unable to get filehandle\n" +, # Croak if unable to get filehandle ERROR => "", HISTORY => [], # Create an array for history },$class; if(! $self->open_log()){ die"Unable to open $self->{LOG}\n"; # Croak if we can't open th +e file } return $self; # Return the object } sub get_log{ my $self=shift; return $$self{LOG}; # Return the log } sub open_log{ my $self=shift; my $path="c:\\ShopTestHarnessLogs"; unless (opendir(DIR,$path)) { system("md c:\\ShopTestHarnessLogs") } if(! open($$self{FILEHANDLE},">>$$self{LOG}")){ $self->log("Unable to open logfile\n"); return 0; # On failure, return 0 } $$self{FILEHANDLE}->autoflush(1); return 1; # On success, return 1 } sub write{ my($self,$msg,$value)=@_; # args == object, message and + optional value my $FH=*{$$self{FILEHANDLE}}; # Make a filehandle string fr +om the blob # Get the local time into an array my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localti +me(time()); my @wdays = qw(Sun Mon Tue Wed Thu Fri Sat); # Make an array o +f weekday names my $weekday = $wdays[$wday]; # Get today's weekday name $year = $year + 1900; # Calculate the current year $mon = $mon + 1; # Calculate the current month # Now format the message with a time stamp in front of the message my $format = sprintf("[$weekday %4d-%02d-%02d %02d:%02d:%02d] $msg +", $year, $mon, $mday, $hour, $min, $sec); if(! print $FH "$format\n"){ # Log it if we cannot print to + the file $self->log("Unable to write to $$self{LOG}: $!\n"); } print "\n$msg \n" if ($value ==1); # Print to monitor as w +ell if value == 1 } sub clear{ # Clear the error (make it undef) my $self=shift; $$self{ERROR}=undef; } sub log{ my ($self,$error,$value)=@_; # Args == object, error messag +e and value $self->clear; # Clear last error from the object $$self{ERROR}=$error; # Add the error message to the ob +ject push @{$$self{HISTORY}},$error; # Push the error into the h +istory array carp "$error\n" if $$self{CARP}; # Carp if an error with th +is object $self->write($error,$value); # Send the message and value t +o "write" sub above } 1;
Here is a driver to test it.
use Logger; # Create the Logger object passing file name my $log=Logger->new(LOG=>"FILE.LOG",CARP=>1); # Call log method passing the message and 1 to print to screen or 0 n +ot to print to screen. $log->log("A",1); $log->log("qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwe +rtyuiopasdfghjklzxcvbnm ",1); $log->log("12345690123456789012345678990",1);

Edited by planetscape - added readmore tags

( keep:0 edit:14 reap:0 )

Replies are listed 'Best First'.
Re: Format ignorance
by shmem (Chancellor) on Oct 05, 2006 at 19:15 UTC

    Ignorance can be mended with reading ;-)

    Read FileHandle. It defines format_name, format_top and so on. Read perlform.

    - my $FH=*{$$self{FILEHANDLE}}; + my $FH = $self->{FILEHANDLE}; + $FH->format_name('FH'); - format $FH = + format FH =

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        I mentioned FileHandle because in the OP, section "Original code", FileHandle is used. Of course IO::File would be the better choice, but since reading is expensive, I pointed to the module at hand.

        With eagerness one naturally ends up with IO::File, since the first sentence in the DESCRIPTION section of FileHandle reads

        NOTE: This class is now a front-end to the IO::* classes.

        :-)

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Thanks shmem,

      That did the trick. I will pore over the references, leveraging off of a now-working example.
Re: Format ignorance
by ysth (Canon) on Oct 06, 2006 at 03:34 UTC
    formats are a lot like (non-anonymous) subs. They have to have real names. If you need to give one an arbitrary name, you can either use $x = "foo"; eval "format $x=\n...\n.\n;" or (5.8+ only) *foo = *bar{FORMAT}; (where bar is some actual format name).