Trying to write a log function


S

Simon

Hi guys!

Hope you can help.
Im a newbie to this, but have some sample code that Im trying to understand.
The goal is that I can successfully write a log function that writes
messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out how
i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

====================================================================== code

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");
printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");
while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);
}

}


$LogFile = "C:\\logs\\$Product.log";

====================================================================== code

So basically, what Im trying to do is, insert a Log function into particular
parts of the script, and wherever I insert the Log function, to write that
line to Product.log.
The above is only a snippet.
Any help will be great.
I just dont know how to call the Log function, or how to actually write it
to be honest.
The below is my objective.

1) Write a log function (subroutine)
2) Being able to call that log subroutine anywhere in my script, and log
messages from that call to a text file.

Thanku in advance.
 
Ad

Advertisements

J

John W. Krahn

Simon said:
Hope you can help.
Im a newbie to this, but have some sample code that Im trying to understand.
The goal is that I can successfully write a log function that writes
messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out how
i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

====================================================================== code

You should have these two lines at the beginning of your program and let perl
help you find mistakes:

use warnings;
use strict;

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");

You should *ALWAYS* verify that your file opened correctly:

open LOG, '>>', $LogFile or die "Cannot open '$LogFile' $!";

This would have caught the error that $LogFile has *no* value here because it
is not assigned a value until later in the program.

printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];

The correct way to get the year (as described in 'perldoc -f localtime') is to
add 1900 to the sixth element of the list returned from localtime so that
expression could be more concisely written as:

printf LOG "%04d/%02d/%02d %02d:%02d:%02d %s\n", $g[ 5 ] + 1900, $g[ 4 ]
+ 1, @g[ 3, 2, 1, 0 ], $_[ 0 ];

printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];

Same as above.

close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");

You should *ALWAYS* verify that your file opened correctly:

open PS, '-|', $PSCMD or die "Cannot open pipe from '$PSCMD' $!";

while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);

And with a pipe you should also verify that it closed correctly:

close PS or warn $! ? "Error closing '$PSCMD' pipe: $!"
: "Exit status $? from '$PSCMD'";



John
 
M

Mumia W.

Hi guys!

Hope you can help.
Im a newbie to this, but have some sample code that Im trying to understand.
The goal is that I can successfully write a log function that writes
messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out how
i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

====================================================================== code

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");
printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");
while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);
}

}


$LogFile = "C:\\logs\\$Product.log";

====================================================================== code

So basically, what Im trying to do is, insert a Log function into particular
parts of the script, and wherever I insert the Log function, to write that
line to Product.log.
The above is only a snippet.
Any help will be great.
I just dont know how to call the Log function, or how to actually write it
to be honest.
The below is my objective.

1) Write a log function (subroutine)
2) Being able to call that log subroutine anywhere in my script, and log
messages from that call to a text file.

Thanku in advance.

These are the problems I see with your program so far:
$LogFile is defined too late for it to be useful for the Log function.
The code in Log is too convoluted even though it probably just prints
the time and some text. Parenthesis are needed with function calls if
Perl hasn't been made aware ahead of time that the function is a function.

This site can help you learn about Perl:
http://perldoc.perl.org/perl.html

After reading that page, you should read "perlintro."
 
S

Simon

Hi Mumia!

Thank you so much for your input and help.
Appreciate your comments.
Thanks again :>)

Mumia W. said:
Hi guys!

Hope you can help.
Im a newbie to this, but have some sample code that Im trying to
understand.
The goal is that I can successfully write a log function that writes
messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out
how i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

======================================================================
code

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");
printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");
while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);
}

}


$LogFile = "C:\\logs\\$Product.log";

======================================================================
code

So basically, what Im trying to do is, insert a Log function into
particular parts of the script, and wherever I insert the Log function,
to write that line to Product.log.
The above is only a snippet.
Any help will be great.
I just dont know how to call the Log function, or how to actually write
it to be honest.
The below is my objective.

1) Write a log function (subroutine)
2) Being able to call that log subroutine anywhere in my script, and log
messages from that call to a text file.

Thanku in advance.

These are the problems I see with your program so far:
$LogFile is defined too late for it to be useful for the Log function. The
code in Log is too convoluted even though it probably just prints the time
and some text. Parenthesis are needed with function calls if Perl hasn't
been made aware ahead of time that the function is a function.

This site can help you learn about Perl:
http://perldoc.perl.org/perl.html

After reading that page, you should read "perlintro."
 
S

Simon

John!

Youre so kind to have spent some time on this for me.
I really appreciate your comments.
Thansk John.

Simon

John W. Krahn said:
Simon said:
Hope you can help.
Im a newbie to this, but have some sample code that Im trying to
understand.
The goal is that I can successfully write a log function that writes
messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out
how i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

======================================================================
code

You should have these two lines at the beginning of your program and let
perl help you find mistakes:

use warnings;
use strict;

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");

You should *ALWAYS* verify that your file opened correctly:

open LOG, '>>', $LogFile or die "Cannot open '$LogFile' $!";

This would have caught the error that $LogFile has *no* value here because
it is not assigned a value until later in the program.

printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];

The correct way to get the year (as described in 'perldoc -f localtime')
is to add 1900 to the sixth element of the list returned from localtime so
that expression could be more concisely written as:

printf LOG "%04d/%02d/%02d %02d:%02d:%02d %s\n", $g[ 5 ] + 1900,
$g[ 4 ] + 1, @g[ 3, 2, 1, 0 ], $_[ 0 ];

printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];

Same as above.

close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");

You should *ALWAYS* verify that your file opened correctly:

open PS, '-|', $PSCMD or die "Cannot open pipe from '$PSCMD' $!";

while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);

And with a pipe you should also verify that it closed correctly:

close PS or warn $! ? "Error closing '$PSCMD' pipe: $!"
: "Exit status $? from '$PSCMD'";



John
 
T

Tim Southerwood

Mumia said:
Hi guys!

Hope you can help.
Im a newbie to this, but have some sample code that Im trying to
understand. The goal is that I can successfully write a log function that
writes messages to a log file.
Please bare with me as I dont fully understand the below code, which is
where I need your gurus expertise.
Here is the code, which is not working, but Id like to try and find out
how i can get it to work to write messages to a log file.
Any help appreciated.
Thank you.

======================================================================
code

sub Log {

@g = localtime time;
open(LOG,">>$LogFile");
printf LOG "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
printf "%02d%02d/%02d/%02d %02d:%02d:%02d $_[0]\n",
sprintf("%02d",(substr sprintf("%03d",$g[5]), 0, 1) + 19),(substr
sprintf("%03d",$g[5]), 1, 2),$g[4]+1,$g[3],$g[2],$g[1],$g[0];
close(LOG);

}

sub WaitForInstall() {

Log " Waiting for installation to complete";
sleep 10;
$finished = 0;
while (!$finished) {
sleep 5;
$finished = 1; # assume we're finished
open(PS,"$PSCMD|");
while (<PS>) {

if ($_ =~ /$Product Setup/i) {
$finished = 0; # not finished
}
elsif ($_ =~ /$Product/i) {
$finished = 0; # not finished
}
}
close(PS);
}

}


$LogFile = "C:\\logs\\$Product.log";

======================================================================
code

So basically, what Im trying to do is, insert a Log function into
particular parts of the script, and wherever I insert the Log function,
to write that line to Product.log.
The above is only a snippet.
Any help will be great.
I just dont know how to call the Log function, or how to actually write
it to be honest.
The below is my objective.

1) Write a log function (subroutine)
2) Being able to call that log subroutine anywhere in my script, and log
messages from that call to a text file.

Thanku in advance.

These are the problems I see with your program so far:
$LogFile is defined too late for it to be useful for the Log function.
The code in Log is too convoluted even though it probably just prints
the time and some text. Parenthesis are needed with function calls if
Perl hasn't been made aware ahead of time that the function is a function.

This site can help you learn about Perl:
http://perldoc.perl.org/perl.html

After reading that page, you should read "perlintro."

I agree, and I would add:

Opening and closing the file on every call to Log() is expensive. One
usually opens it once and then keeps the file handle around.

In this case, it might be considered "good manners" to have the program
respond to SIGHUP to close and reopen the log file for the benefit of
logrotation, though logrotate can work around this if necessary.

Hint to the OP: Try POSIX::strftime()

Cheers

Tim
 
Ad

Advertisements

J

Jürgen Exner

Tim said:
Opening and closing the file on every call to Log() is expensive.
True.

One
usually opens it once and then keeps the file handle around.

Depends. If you want to capture the last breath of your program before it
dies an untimely death then you don't want to risk loosing its last words in
an unsaved buffer.

jue
 
T

Tim Southerwood

Jürgen Exner said:
Depends. If you want to capture the last breath of your program before it
dies an untimely death then you don't want to risk loosing its last words
in an unsaved buffer.

jue

That's fair, but then it would still be cheaper to sysopen the file with
O_SYNC
and call syswrite(). Imagine that the program gets into a whinge-loop an
spews messages at the rate of 100's per second which isn't unknown. A basic
step like this can make a noticeable difference.

Cheers

Tim
 
P

Peter J. Holzer

Opening and closing the file on every call to Log() is expensive. One
usually opens it once and then keeps the file handle around.
Yup.


In this case, it might be considered "good manners" to have the program
respond to SIGHUP to close and reopen the log file for the benefit of
logrotation, though logrotate can work around this if necessary.

Another way is to switch log files automatically from the logging
routine. A handy way to do this is to include a timestamp (e.g. the
current day) in the log file name and for every entry (or at other
convenient moments such as when a new client connects) check if the log
file name has changed:


{
my $log_filename_template = "/var/log/whatever/%Y-%m-%d";
my $log_filename = '';
my $log_fh;

sub log {
my ($msg) = @_;
my @lt = localtime();
my $ts = strftime("%Y-%m-%dT%H:%M:%S%z", @lt);
my $fn = strftime($log_filename_template, @lt);
if ($fn ne $log_filename) {
if ($log_fh) {
close($log_fh) or die "error closing $log_filename: $!";
}
$log_filename = $fn;
open($log_fh, ">>", $log_filename) or die "error opening $log_filename: $!";
$log_fh->autoflush(1);
}
$log_fh->print("$ts $msg\n") or die "error writing $log_filename: $!";
}
}

You still need a cronjob to compress and/or delete old logfiles.

hp
 
Ad

Advertisements

P

Peter J. Holzer

Depends. If you want to capture the last breath of your program before it
dies an untimely death then you don't want to risk loosing its last words in
an unsaved buffer.

You should generally turn autoflush on on log files. Apart from the
reason you just mentioned there are two others:

1) If your program only prints log entries only infrequently, it may
take a long time until the (typically 4kB or 8kB) buffer fills up.
Normally you want every log message in the log immediately, not a
bunch of messages every few hours.

2) Buffers usually have a fixed size, so the blocks written to the log
file will not start and end at line boundaries. If you have several
processes writing to the same log file lines will be mixed. If you
flush after every line that can't happen (at least on Unix, the
kernel makes sure that a single write on a file in append mode is
written atomically). For the same reason you should write the whole
message with a single print call.

hp
 

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

Top