in reply to Timelocal out of range message

G'day itis.guptak,

Welcome to the monastery.

Please provide a short script that reproduces your problem. How to do this is explained in "How do I post a question effectively?".

Without seeing any code or data, we are not able to "find the reason for this error". However, the only instance I can think of giving "Day '29' out of range 1..28" would be during February of a non-leap year.

Please ensure you haven't made a simple syntax error (e.g. number and order of timelocal() arguments) by checking the Time::Local documentation.

-- Ken

Replies are listed 'Best First'.
Re^2: Timelocal out of range message
by itis.guptak (Initiate) on Feb 03, 2014 at 07:36 UTC

    Thanks, Ken. Let me just explain what this script does. It pulls the systems message file from a list of hosts and put the content in a single file output on a central server from where it's run as cron job. I'm pasting a portion of code that's responsible for timelocal() execution in the script. The code I'm pasting contains three subroutines: addMessage(), processFile(), getLogsSCP(). getLogsSCP() will scp the files to central server. processFile() is called within getLogsSCP() and processFile() furthur calls addMessage(). Finally it's the addMessage() that invokes timelocal(). I've also pasted some variables used for computing the parameters passed to the timelocal function. This line of the code is generating the error.

    my $logtime = timelocal(${sec}, ${min}, ${hour}, ${mday}, ${mon}, ${current_year} - ${new_yea +r});

    Code

    sub getLogsSCP { my @hosts = @_; dprint "Getting logs for the last ${cutoff} hours"; dprint " from " . @hosts . " hosts\n"; # Build command to list log files # Using find allows us to scan only files that are new enough my $ssh_command = "find"; $ssh_command .= " @messages_files"; $ssh_command .= " -mtime -" . (int(${cutoff} / 24) + 1); my $nHosts = 1; foreach (@hosts) { chomp; my $host = $_; $current_host = ${host}; $last{${host}} = ""; my $c = 0; while (<READER>) { chomp; my $file = $_; my $tmpfile = "/tmp/logmon.${host}.$hnow{year}$hnow{mon}$hnow{md +ay}.$ENV{LOGNAME}"; # Copy log file dprint localtime() . " Copying ${file} to ${tmpfile}\n"; my $scp = Net::SCP->new({"host" => ${host}}); $scp->get(${file}, ${tmpfile}); # Process log file my $size = (stat("${tmpfile}"))[7]; if (! defined(${size})) { dprint localtime() . " Failed to copy ${file} from ${host}\n"; addFakeMessage(${host}, "FAILED TO COPY ${file} FROM ${host}") +; $total_count++; next; } dprint localtime() . " Parsing ${tmpfile} (${size} bytes)\n"; open(FD, "${tmpfile}") or next; unlink "${tmpfile}"; $c += processFile(\*FD, ${tmpfile}, ${host}); close(FD); } push @emptyhosts, ${host} if ($c == 0); $total_count += $c; close(*READER); close(*WRITER); close(*ERR); } dprint "\n"; } # Process a log file (or stream) sub processFile() { my $FD = shift; # Caller must open and close file descrip +tor my $file = shift; my $host = shift; my $c = 0; my $line = 1; while (<FD>) { # Log file is too big if ($line++ > ${max_messages}) { dprint "\n" . localtime() . " Too many messages in ${file}"; addFakeMessage(${host}, "STOPPED PROCESSING ${file} AFTER ${max_ +messages} MESSAAGES (please rotate)"); $total_count++; last; } dprint "${line}..." if (($line % 10000) == 0); my $retval += addMessage($_); if (${retval} < 0) { $c = 0; } else { $c += ${retval}; } } dprint "\n" if (${line} > 10000); return ${c} ; } sub addMessage($) { my $msg = shift; chomp ${msg}; # Skip blank lines if (${msg} =~ /^$/) { $reason = "blank"; return 0; } # Parse message my ($month, $mday, $tm, $host, @message) = split(/ ?/, ${msg}); my ($hour, $min, $sec) = split(/:/, ${tm}) if (defined(${tm})); # Skip line if we don't know the hostname if (! defined(${host}) || ${host} eq "") { $reason = "hostname" ; re +turn 0; } # Skip lines that don't look like syslog messages unless (${tm} =~ /[0-2]\d:[0-5]\d/) { $reason = "tm = ${tm}"; return + 0; } # Skip lines that are too old my $mon = $month_to_mon{${month}}; my $logtime = timelocal(${sec}, ${min}, ${hour}, ${mday}, ${mon}, ${current_year} - ${new_yea +r}); <----------------- This line is producing the error. if ((${mon} == 0) && (${mday} == 1) && (${new_year} == 1)) { # Special case for Jan 1 (only!) $logtime = timelocal(${sec}, ${min}, ${hour}, ${mday}, ${mon}, ${current_year}); } $logtime -= ((int($offsets{${host}}) / 100) * 100) if (defined($offsets{${host}})); if (${logtime} < ${then}) { $reason = "too old"; return 0; } # Reset host if line is from the future; we may have messages from o +ne # year ago. Note that this may make the global counts wrong. if (${logtime} > (time + 3600)) { # Allow 1 hour slack time $last{${host}} = ""; $counts{${host}} = 0; delete($messages{${host}}); undef($times{${host}}{oldest}); undef($times{${host}}{newest}); $reason = "future"; return -1; } my %month_to_mon = # Convert month names to numbers (Jan +== 0) ( "Jan" => 0, "Feb" => 1, "Mar" => 2, "Apr" => 3, "May" => 4, "Jun" => 5, "Jul" => 6, "Aug" => 7, "Sep" => 8, "Oct" => 9, "Nov" => 10, "Dec" => 11, "JAN" => 0, "FEB" => 1, "MAR" => 2, "APR" => 3, "MAY" => 4, "JUN" => 5, "JUL" => 6, "AUG" => 7, "SEP" => 8, "OCT" => 9, "NOV" => 10, "DEC" => 11); my @mon_to_month = # Convert month numbers to names (0 == + Jan) qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);

      I wrote:

      "Please provide a short script that reproduces your problem. How to do this is explained in "How do I post a question effectively?"."

      Had you followed that link, you would have seen, in big, friendly letters, at the top of the screen:

      Paste actual code that reproduces the problem ...

      You haven't posted actual code. You haven't posted code that reproduces your problem.

      In addition, hundreds of lines of code is not a "short script": a dozen or so lines normally suffices for this sort of task. If you ever do need to post large tracts of code, data, etc., wrap it in <spoiler>...</spoiler> or <readmore>...</readmore> tags: see "Markup in the Monastery" and "Writeup Formatting Tips".

      What you have posted appears to have been copied from your browser. It looks like the code you posted a couple of hours before in this thread; it includes all the '+' signs at the beginning of lines (that indicate that a line wrapped) which are not part of the Perl code.

      If you can post a short script that shows Time::Local::timelocal() giving your "Timelocal out of range message", I'll be happy to look at it further.

      In writing a short script to reproduce your problem, you'll often gain insights into why your original code was having issues.

      Something else you can do is to add print statements to your original code to see what actual values are being passed to your functions. This can often point to where the problem lies.

      -- Ken