3
\$\begingroup\$

I currently have a system which loops through a bunch of my website domains and checks their status and sends me a notification letting me know if they are up or down. The stripped down version of the relay code is below, I've removed the email/DB update code etc.

It pings a transponder (a file on the client website server) which returns 'SUCCESS' or whatever the error it has encountered and returns that as a string.

function checkStatus($domain){
  $statusArray = array();

  $url = $domain . '/transponder.php';

  $statusArray['transponder_response'] = file_get_contents($url);

  if($statusArray['transponder_response'] == 'SUCCESS'){
    //all is well
  }else{
    //all is not well
    $statusArray['transponder_code'] = get_headers($url, 1);
    //send code and response via email to admin
  }

  return $statusArray;
}

The transponder code is such:

$dbInfo['host'] = '';
$dbInfo['dbname'] = '';
$dbInfo['user'] = '';
$dbInfo['pass'] = '';

$link = mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['pass'], $dbInfo['dbname']);

if(mysqli_connect_errno()){
  printf('Connect failed: %s\n', mysqli_connect_error());
  exit();
}

if($result = mysqli_query($link, 'SELECT 1')){
  if(mysqli_num_rows($result)) echo 'SUCCESS';
  mysqli_free_result($result);
}

mysqli_close($link);

A 'SUCCESS' response means that the site domain is resolving, PHP is working and DB is working.

Can anyone point me in a direction to make this more accurate and effective for site monitoring?

\$\endgroup\$
2
\$\begingroup\$

When you say checkStatus($domain), the parameter should either be actually just a domain (without protocol identifier), or you should just specify the full URI. When in doubt, you shouldn't hardcode /transponder.php.

As for the task of status monitoring - testing the database connectivity is certainly not wrong, but keep in mind that far more can go wrong. If you really want to check if the site is working, don't test against a minimal test script, but a real page of that site. Preferably one which does involve as many systems as possible, and check if the output is the expected.

Why? As I said before, there are more possible errors than just the database connection. Commonly you can also run into problem with the session storage, failing server side caches (APC, memcached and alike), resource shortages (e.g. PHP going OOM), and various more.

You should probably also record response times, not only response status. If your server fails to respond timely, it's a warning sign that you should react to immediately before there is a complete outage.

Last, but not least, don't just test a single status page. If you have access to it, rather check the error logs if there were any events in the past interval. Especially during load spikes, not necessarily every request is going to fail. But an accumulation of failures can be easily read from the logs, and should be dealt with. Make sure your application does log warnings and errors properly.

\$\endgroup\$
  • \$\begingroup\$ You have some very interesting points, I will implement these and come back to you soon \$\endgroup\$ – PavKR Jun 21 '16 at 7:42
1
\$\begingroup\$

I think @Ext3h gives some good advice around perhaps making the test more meaningful, by exercising key elements necessary for proper site operation and for looking at multiple vectors (including logs) for overall site health.

I will add some comments on the code itself. I have added comments within code context.

function checkStatus($domain){
  // you are doing nothing here to validate that valid value for $domain is being passed

  $statusArray = array();

  $url = $domain . '/transponder.php';

  // I would consider using cURL or something more full featured that file_get_contents
  // cURL would allow you to view much more in with regards to request and response data
  $statusArray['transponder_response'] = file_get_contents($url);

  // use exact comparison here (===)
  if($statusArray['transponder_response'] == 'SUCCESS'){
    //all is well
  }else{
    //all is not well

    // here if you used cURL, you would already have header info from request
    // rather than making second request to server, which could actually get
    // different response
    $statusArray['transponder_code'] = get_headers($url, 1);
    //send code and response via email to admin
  }

  return $statusArray;
}

And for server script:

// it makes no sense to store DB connection info in this script
// you should use EXACT same configuration used by the application itself
// otherwise who is to say this configuration is the same as what you are trying to test
$dbInfo['host'] = '';
$dbInfo['dbname'] = '';
$dbInfo['user'] = '';
$dbInfo['pass'] = '';

$link = mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['pass'], $dbInfo['dbname']);

if(mysqli_connect_errno()){

  // I would consider logging this information not printing it
  // your script has not security settings at all, so you are exposing this
  // info to a potential attacker
  printf('Connect failed: %s\n', mysqli_connect_error());
  exit();
}

// you should handle edge cases and not just happy path here
// and echo appropriate failure message
if($result = mysqli_query($link, 'SELECT 1')){
  // why do you care about numbers of rows? You are only doing a trivial query anyway
  // so if the query succeeds, you know you are good to go
  // perhaps consider a less trivial query to , for example
  // make sure you can access a critical table.
  if(mysqli_num_rows($result)) echo 'SUCCESS';
  mysqli_free_result($result);
}

mysqli_close($link);

// consider sending appropriate header 200 for OK, 500 for error
// such that calling client need only make a HEAD request against this script
\$\endgroup\$
  • \$\begingroup\$ Thanks Mike, you and @Ext3h have given some good advice, I will update my code and add it to my question. One thing though, what is the time difference for execution of file_get_contents to cURL? \$\endgroup\$ – PavKR Jun 21 '16 at 21:28
  • \$\begingroup\$ @thePav Please DO NOT modify your original question. That would make the question and comment non-intelligible for future users. If you want to have an iterative review, please post it in a different question. WRT time difference between the two approaches, you would have to test yourself. My guess is you will find minimal difference with regards to the overall time to fulfill the request. \$\endgroup\$ – Mike Brant Jun 21 '16 at 21:32
  • \$\begingroup\$ Ok, thanks Mike, I will get back to you soon! \$\endgroup\$ – PavKR Jun 21 '16 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.