Server Monitoring with PHP and Shell Scripts — Automated Checks Using CRON
Monitoring server performance is important for ensuring stable operations.
By using PHP’s shell_exec function together with commands like top and vmstat + awk, you can retrieve CPU usage and check for zombie processes.
This article introduces monitoring scripts that use these commands and explains how to automate regular checks by configuring them in CRON.
Example CRON entry for running the monitoring script every 5 minutes:
crontab -e # Add the following line */5 * * * * /usr/bin/php /path/monitor.php > /dev/null 2>&1
"monitor.php" File
<?php
//Mail From
$from="webmaster@hoge.jp";
//Mail To
$to="webmaster@hoge.jp";
//Subject
$subject="Server Warning";
//Threshold settings (example)
$thresh=[
"process"=>[
"zombie"=>10 //10 or more zombie processes
],
"cpu"=>[
"ussy"=>95, //5-second average CPU usage >= 95%
"wa"=>80 //IO wait time ratio >= 80%
],
];
//Warning messages
$warning=[
"process"=>[
"zombie"=>"The number of zombie processes is %d, which exceeds the threshold (".$thresh["process"]["zombie"].").\r\n"
],
"cpu"=>[
"ussy" =>"The 5-second average CPU usage is %f, which exceeds the threshold (".$thresh["cpu"]["ussy"].").\r\n",
"wa" =>"The IO wait ratio is %f, which exceeds the threshold (".$thresh["cpu"]["wa"].").\r\n".
"Disk IO or network IO is increasing.\r\n"
],
];
$command='top -b -n 1|head -n 4';
$ret_top=shell_exec($command);
$ret_top=explode(",", preg_replace('/\r\n|\n/', ',', $ret_top));
$command='vmstat 1 5 | awk \'NR>2 {us+=$13; sy+=$14; id+=$15; wa+=$16} END {print us/5, ",", sy/5, ",", id/5, ",", wa/5}\'';
$ret_vmstat=shell_exec($command);
$ret_vmstat=explode(",", $ret_vmstat);
$val=[
"process"=>[
"running" => intval(preg_replace('/[^\d]/','',$ret_top[7])),
"sleeping" => intval(preg_replace('/[^\d]/','',$ret_top[8])),
"stopped" => intval(preg_replace('/[^\d]/','',$ret_top[9])),
"zombie" => intval(preg_replace('/[^\d]/','',$ret_top[10])),
],
"memory"=>[
"free" => intval(preg_replace('/[^\d]/','',$ret_top[20])),
"used" => intval(preg_replace('/[^\d]/','',$ret_top[21])),
"buf_cache" => intval(preg_replace('/[^\d]/','',$ret_top[22])),
],
"cpu"=>[
//User mode + system mode CPU usage
"ussy" => floatval($ret_vmstat[0])+floatval($ret_vmstat[1]),
"id" => floatval($ret_vmstat[2]), //Idle ratio
"wa" => floatval($ret_vmstat[3]), //IO wait ratio
]
];
$message=[];
if($val["process"]["zombie"]>=$thresh["process"]["zombie"]){
$message[]=sprintf($warning["process"]["zombie"], $val["process"]["zombie"]);
}
if($val["cpu"]["ussy"]>=$thresh["cpu"]["ussy"]){
$message[]=sprintf($warning["cpu"]["ussy"], $val["cpu"]["ussy"]);
}
if($val["cpu"]["wa"]>=$thresh["cpu"]["wa"]){
$message[]=sprintf($warning["cpu"]["wa"], $val["cpu"]["wa"]);
}
if(count($message)>0){
$head = "From: ".$from."\r\n".
"Reply-To: ".$from;
$body = implode("\r\n", $message);
$body.= "\r\n".
"Processes (running): " .$val["process"]["running"]."\r\n".
"Processes (sleeping): " .$val["process"]["sleeping"]."\r\n".
"Processes (stopped): " .$val["process"]["stopped"]."\r\n".
"Processes (zombie): " .$val["process"]["zombie"]."\r\n".
"\r\n".
"Memory (free): " .$val["memory"]["free"] ."KB\r\n".
"Memory (used): " .$val["memory"]["used"] ."KB\r\n".
"Memory (buffer/cache): ".$val["memory"]["buf_cache"] ."KB\r\n".
"\r\n".
"CPU (usage): " .$val["cpu"]["ussy"] ."KB\r\n".
"CPU (idle): " .$val["cpu"]["id"] ."KB\r\n".
"CPU (IO wait): " .$val["cpu"]["wa"] ."KB\r\n";
mb_language('uni');
mb_send_mail($to, $subject, $body, $head);
}
