In this article we introduced a ping monitoring perl script. We talked about the main routine in this article. Now, let’s go over the printtime() and ckserv() functions.
The printtime function simply writes a timestamp to mon.txt:
sub printtime{ open (PM,">> mon.txt"); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); $mon++; $year=$year+1900; print PM "\n".$mon."/".$mday."/".$year."-".$hour.":".$min."\n"; close PM; } |
The >> in the open line appends the output to the bottom of the file. For a tutorial on creating time stamps with perl, check out this article.
The ckserv routine is the function that manages scheduling and notification:
sub ckserv{ #Check the current server $currentserver=@_[0]; #The first argument passed $currentip=@_[1]; $found=0; open (SP, "schedule.txt"); while (<SP>){ chomp; s/((?:\w|-)+),(\w+) (\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+) to (\d+)\/(\d+)\/ (\d+) (\d+):(\d+):(\d+)/ $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14/; # $1 - servername # $2 - ignore once|weekly|monthly # $3 - begin month # $4 - begin day # $5 - begin year # $6 - begin hour # $7 - begin minute # $8 - begin second # $9 - end month # $10 - end day # $11 - end year # $12 - end hour # $13 - end minute # $14 - end second $timeb=timelocal($8,$7,$6,$4,$3-1,$5); #full time of beginning of ignore (default time # format in seconds since 1/1/1970) $timee=timelocal($14,$13,$12,$10,$9-1,$11); #full time of end of ignore $timebdwk=timelocal($8,$7,$6,1,0,0); #hour/min/sec portion of beginning of ignore in time format $timeedwk=timelocal($14,$13,$12,1,0,0); #hour/min/sec portion of end of ignore in time format ($secb,$minb,$hourb,$mdayb,$monb,$yearb,$wdayb,$ydayb,$isdstb)=localtime($timeb); #split out the parts of the begin of ignore ($sece,$mine,$houre,$mdaye,$mone,$yeare,$wdaye,$ydaye,$isdste)=localtime($timee); #split out the parts of the end of ignore ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); #split out the parts of the current time $timeedwkn=timelocal($sec,$min,$hour,1,0,0); #hour/min/sec portion of current time in time format if ((($2 eq 'weekly' && $timeedwkn le $timeedwk && $timeedwkn ge $timebdwk && $wdayb eq $wday) || ($2 eq 'monthly' && $timeedwkn le $timeedwk && $timeedwkn ge $timebdwk && $mdayb eq $mday) || ($2 eq 'once' && time le $timee&& time ge $timeb)) && (($1 eq 'everybodydown') || ($1 eq $currentserver))){ $found=1; } } if(pf()){ # 10 pings has to fail 4 times before Mon Pages open (PM,">> mon.txt"); print PM "10 pings to server ".$currentserver.", but router passed \n"; close PM; printtime(); if(pf()){ open (PM,">> mon.txt"); print PM "20 pings to server ".$currentserver.", but router passed \n"; close PM; printtime(); if(pf()){ open (PM,">> mon.txt"); print PM "30 pings to server ".$currentserver.", but router passed \n"; close PM; printtime(); if(pf()){ if($found ne 1){ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); $mon++; my %mail = ( To => 'agatha@nospam.com', From => 'pingmon@nospam.com', Message => $text, Subject => $currentserver." is down!", SMTP => '16.4.23.4' ); sendmail(%mail) or die $Mail::Sendmail::error; open (PM,">> mon.txt"); print PM "Server down -- Sending Page\n"; close PM; } else{ my %mail = ( To => 'agatha@nospam.com', From => 'pingmon@nospam.com', Message => $text, Subject => $currentserver." Scheduled Downtime", SMTP => '16.4.23.4' ); sendmail(%mail) or die $Mail::Sendmail::error; open (PM,">>mon.txt"); print PM "Server down -- scheduled\n"; close PM; } } printtime(); } } } } |
This routine is called with two arguments: (hostname, ip). Note that we are not relying on name resolution for this system to work. @_ holds these arguments. The hairy part is determining whether the event is scheduled. $found is set to 0, but if there is a match in the schedule, it is set to 1. Let’s take one line from schedule.txt:
xsrv-49,once 05/26/03 8:50:00 to 06/15/00 19:50:00 |
What we want to do is pull out fourteen bits of this string: the server name, the frequency of the outage, and the bits of the start and finish times. The trickiest match is $1, which is matched by ((?:\w|-)+). The ?: part clusters without creating a backreference. That is $1 is any number of word characters or -. This also means that with this script the only valid hostnames are word characters or -. Because of the ?:, we don’t capture the individual word or – characters. The rest of the matches are pretty straightforward. We just match word characters or digits.
Next, we use the timelocal function from the Time module to convert the times into something we can compare. For instance, if the frequency is weekly, then we need to take the date and calculate the actual day of the week. So, if you want to ignore a particular server every Friday at a certain time, the start time would be the date of the first Friday you want to ignore. Subsequent Fridays would be calculated. Everybodydown will ignore all alerts. Just add an x as the first character in the schedule.txt rule if you want to disable the disable rule. 🙂 It could be anything, since this just makes it so the hostname won’t match.
We then ping the servers with pf(). If pf() is true, then the ping failed and the router was OK. We’ll detail the remaining functions in the final article. If pf() fails four times and there was no match, then the event is logged and either a page is sent or ignored based on the schedule.
Don’t rely on this script for production servers unless you know exactly what you are doing, and are sure that this script fits your needs. Do feel free to encorporate bits of the script as you need, or the whole script if you desire. Credit NetAdminToools, though, if you feel like it. 🙂 Please read our terms of use.
There are five parts to this article:
Introduction
Main Routine
Check/Log Routines
Adding Perl Mods
pf and rf routines
Related Post: Best Ping Monitoring Software