PHP script for server ping monitoring
I’ve been using a PHP script I wrote to monitor whether some of our servers are alive or dead using ping, and send an alarm email if there is no response from the server for a certain period of time. It wasn’t working properly, and today I finally fixed it.
The script can be run from the command line and allows you to define the ping target or destination (the server) you want to monitor, the name of the machine you are pinging from (useful if you’re pinging to and from a matrix of machines) and the email address you would like to send any alarm emails to. It seems to work well on a couple of Linux machines I tried it on.
You run the script using e.g. the following command:
…where you need to put the path to the php package in your setup instead of “/usr/bin/php”, you need to put the path to the PHP script (I named it ping-host.php but you could call it something different), -h is the “host” you are pinging, -l is the name of the “localhost”, i.e. the machine you are pinging from, and -e is the email address (or multiple email addresses) you want to send any alarm mails to.
I have an “email to SMS” address as one of the alarm message recipient, so I get a text (SMS) message on my GSM mobile phone if one of the servers I’m monitoring has been down for 10 minutes or 25 minutes. You could also run a whole network monitoring project with this, using it to ping routers or switches.
I’ll put the script into the posting below, but in order to run this, you also need a table in a database which looks like this:
mon_host_ping_id int(5) NOT NULL auto_increment,
mon_host_ping_hostname varchar(128) NOT NULL default ‘’,
mon_host_ping_factor bigint(16) default NULL,
mon_host_ping_lastupdt timestamp(14) NOT NULL,
PRIMARY KEY (mon_host_ping_id),
UNIQUE KEY mon_host_ping_hostname (mon_host_ping_hostname)
) TYPE=MyISAM;
- You should just be able to cut-and-paste that into the database
I just run this script on a cron job once a minute (feel free to alter the values you use) for each server to be monitored. The line in the crontab looks like this:
Every time you add a new server to the ping list in your crontab you’ll also need to add a row in the mon_host_ping table in the database with its mon_host_ping_factor set to zero:
Query OK, 1 row affected (0.00 sec)
Okay, so now here’s the code for the script, ping-host.php :
## This script was originally published by Sam Critchley on 2005-10-25
##See http://blog.a2b.cc for more details and check out http://www.a2b.cc
##to see a great (geo)location-based search engine while you’re at it!
## MySQL config section
// Define users, passwords, etc
DEFINE (DB_USER, “dbusername”);
DEFINE (DB_PASSWORD, “dbpassword”);
// Define the host which the database is running on (usually localhost)
DEFINE (DB_HOST, “localhost”);
// Define the name of the database being used
DEFINE (DB_NAME, “dbdatabasename”);
// Connect to the MySQL server
$db_connection = @mysql_connect (DB_HOST, DB_USER, DB_PASSWORD) or die (‘Could not connect to the MySQL server sorry: ‘ . mysql_error());
// Select the right database
mysql_select_db (DB_NAME) or die (‘Could not select the database: ‘ . mysql_error());
## End MySQL config section
## Main script
// Work out the variables from the arguments on the command line
// First get the -h, -l and -e arguments from the command issued
// and put them into an array call $getoptarray
$getoptarray = getopt(“h:l:e:”);
// Then derive the pinged hostname, the source machine, and the email address
// to send a warning mail to, from the argument-derived variables
$hostname = $getoptarray[h];
$localhost = $getoptarray[l];
$monitoremailaddress = $getoptarray[e];
// Now run an exec command to ping the hostname and grab the output
$str=exec(“ping -c 1 -w 1 $hostname”,$a,$a1);
// If there’s some output from the ping command then the ping has succeeded
if(strlen($str)>1){
// Ping response has been received, therefore can update the database record to set
// mon_host_ping_factor back to 0
// The script uses a database table called mon_host_ping and has columns
// mon_host_ping_hostname = hostname of the host to be pinged
// mon_host_ping_factor = number of times in a row host has been pinged unsuccessfully
// This database query sets mon_host_ping_factor to 0 if there’s a successful ping
$query = “update mon_host_ping set mon_host_ping_factor = 0 where mon_host_ping_hostname = ‘$hostname’”;
$query_db=mysql_query($query, $db_connection) or die(“Could not run the SQL Query”);
// If there is no output from the ping command then the ping has not succeeded
// and you should generate an alarm mail if it hasn’t succeeded for 10 minutes
// or 25 minutes (alter these values to suit)
} else {
// Generate a database query adding 1 to mon_host_ping_factor if the ping is
// unsuccessful
$query2 = “update mon_host_ping set mon_host_ping_factor = mon_host_ping_factor+1 where mon_host_ping_hostname = ‘$hostname’”;
$query_db2=mysql_query($query2, $db_connection) or die(“Could not run the SQL Query”);
// Now go and grab the mon_host_ping_factor back again, and send a mail if
// it’s equal to 10 or 25 (minutes assuming you’re running this script on a
// cron job every 1 minute)
// Generate a MySQL query to work out what mon_host_ping_factor is
$query3 = “select * from mon_host_ping where mon_host_ping_hostname = ‘$hostname’”;
$query_db3=mysql_query($query3, $db_connection) or die(“Could not run the SQL Query”);
// and then put the result into an array
$row = @mysql_fetch_object($query_db3);
// And put the mon_host_ping_factor into a variable
$hostfactor = $row -> mon_host_ping_factor;
// Now send an alert email to the address specified in the command line if
// the ping has been unsuccessful 10 or 25 minutes in a row
if (($hostfactor == 10) or ($hostfactor == 25)) {
// Set the body of the message
$emessage = “ALERT - $hostname unpingable from $localhost for $hostfactor min”;
// Set the name for the From: part of the email
$myname = “My Service server monitoring”;
// Set the originator’s email address
$myemail = “monitoring@example.com”;
// Get the address to which the email will be sent from the command line variable
$site_email = $monitoremailaddress;
// Now set the headers to be added to the email
$headers .= “MIME-Version: 1.0\r\n“;
$headers .= “Content-type: text/html; charset=iso-8859-1\r\n“;
$headers .= “From: “.$myname.” < “.$myemail.“>\r\n“;
$headers .= “X-Mailer: My Service Mailserv”;
// Now use the PHP mail() function to send the email to the recipient(s)
mail($site_email, “ALERT - $hostname unpingable from $localhost for $hostfactor min”, $emessage, $headers);
}
}
## End main script
?>
I also learnt how to use the PHP getopt() function properly to import command-line arguments into a PHP script. If you’ve read this far, you may have noticed that the script used the following PHP line:
// Then derive the pinged hostname, the source machine, and the email address
// to send a warning mail to, from the argument-derived variables
$hostname = $getoptarray[h];
$localhost = $getoptarray[l];
$monitoremailaddress = $getoptarray[e];
This finally worked, but I had to try various combinations to get it working:
I finally worked out that you need to put all the arguments you’re expecting in the original getopt() function as it can only be called once on a script run from the command line - in this case the arguments are all dumped into the $getoptarray array and you can then pull them out individually using something like this:
$localhost = $getoptarray[l];
$monitoremailaddress = $getoptarray[e];
Any queries, just post a comment. Better still, have a look at A2B, download the free GPS software, add your blog, pass on the recommendation to a few other people, and then post a comment.
41 Comments
