Trying to write a log function

Discussion in 'Perl Misc' started by Simon, Jul 4, 2007.

  1. Simon

    Simon Guest

    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.
    Simon, Jul 4, 2007
    #1
    1. Advertising

  2. Simon wrote:
    >
    > 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
    --
    Perl isn't a toolbox, but a small machine shop where you
    can special-order certain sorts of tools at low cost and
    in short order. -- Larry Wall
    John W. Krahn, Jul 4, 2007
    #2
    1. Advertising

  3. Simon

    Mumia W. Guest

    On 07/03/2007 09:35 PM, Simon wrote:
    > 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."
    Mumia W., Jul 4, 2007
    #3
  4. Simon

    Simon Guest

    Hi Mumia!

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

    "Mumia W." <> wrote in message
    news:b8Kii.4035$...
    > On 07/03/2007 09:35 PM, Simon wrote:
    >> 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."
    Simon, Jul 4, 2007
    #4
  5. Simon

    Simon Guest

    John!

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

    Simon

    "John W. Krahn" <> wrote in message
    news:i_Fii.26076$xk5.3904@edtnps82...
    > Simon wrote:
    >>
    >> 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
    > --
    > Perl isn't a toolbox, but a small machine shop where you
    > can special-order certain sorts of tools at low cost and
    > in short order. -- Larry Wall
    Simon, Jul 4, 2007
    #5
  6. Mumia W. wrote:

    > On 07/03/2007 09:35 PM, Simon wrote:
    >> 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
    Tim Southerwood, Jul 4, 2007
    #6
  7. Tim Southerwood wrote:
    > 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
    Jürgen Exner, Jul 4, 2007
    #7
  8. Jürgen Exner wrote:

    > Tim Southerwood wrote:
    >> 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


    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
    Tim Southerwood, Jul 4, 2007
    #8
  9. On 2007-07-04 11:23, Tim Southerwood <> wrote:
    >
    > 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


    --
    _ | Peter J. Holzer | I know I'd be respectful of a pirate
    |_|_) | Sysadmin WSR | with an emu on his shoulder.
    | | | |
    __/ | http://www.hjp.at/ | -- Sam in "Freefall"
    Peter J. Holzer, Jul 7, 2007
    #9
  10. On 2007-07-04 11:26, Jrgen Exner <> wrote:
    > Tim Southerwood wrote:
    >> 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.


    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


    --
    _ | Peter J. Holzer | I know I'd be respectful of a pirate
    |_|_) | Sysadmin WSR | with an emu on his shoulder.
    | | | |
    __/ | http://www.hjp.at/ | -- Sam in "Freefall"
    Peter J. Holzer, Jul 7, 2007
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Henrik_the_boss
    Replies:
    0
    Views:
    2,630
    Henrik_the_boss
    Nov 5, 2003
  2. Suhail Salman
    Replies:
    2
    Views:
    4,893
  3. Amratash
    Replies:
    0
    Views:
    500
    Amratash
    Apr 13, 2004
  4. Petterson Mikael

    Write to error log using redirect:write

    Petterson Mikael, Sep 11, 2006, in forum: XML
    Replies:
    1
    Views:
    828
    Joe Kesselman
    Sep 11, 2006
  5. Replies:
    0
    Views:
    1,263
Loading...

Share This Page