Home arrow PHP arrow Page 4 - A Basic Monitoring Engine in PHP

Sample ServiceLogger Process - PHP

Last week, we continued our discussion of PHP standalone scripts with child processes and more. This week, we conclude our discussion and bring together what you've learned. The third of three parts, this article is excerpted from chapter five of the book Advanced PHP Programming, written by George Schlossnagle (Sams; ISBN: 0672325616).

  1. A Basic Monitoring Engine in PHP
  2. Giving Up Privileges
  3. Combining What You've Learned: Monitoring Services
  4. Sample ServiceLogger Process
By: Sams Publishing
Rating: starstarstarstarstar / 5
September 14, 2006

print this article



Here is a sample ServiceLogger process that sends an email to an on-call person when a service goes down:

class EmailMe_ServiceLogger implements
ServiceLogger { public function log_service_event(ServiceCheck
$service) { if($service->current_status ==
ServiceCheck::FAILURE) { $message = "Problem with
{$service->description()}\r\n"; mail('oncall@example.com', 'Service Event',
$message); if($service->consecutive_failures() > 5) { mail('oncall_backup@example.com', 'Service
Event', $message); } } } public function log_current_status(ServiceCheck
$service) { return; } }

If the failure persists beyond the fifth time, the process also sends a message to a backup address. It does not implement a meaningful log_current_status() method.

You implement a ServiceLogger process that writes to the PHP error log whenever a service changes status as follows:

class ErrorLog_ServiceLogger implements
ServiceLogger { public function log_service_event(ServiceCheck
$service) { if($service->current_status() !==
$service->previous_status()) { if($service->current_status() ===
ServiceCheck::FAILURE) { $status = 'DOWN'; } else { $status = 'UP'; } error_log("{$service->description()} changed
status to $status"); } } public function log_current_status(ServiceCheck
$service) { error_log("{$service->description()}: $status"); } }

The log_current_status() method means that if the process is sent a SIGUSR1 signal, it dumps the complete current status to your PHP error log.

The engine takes a configuration file like the following:

<description>OmniTI HTTP Check</description>
<description>Home Page HTTP Check</description>

When passed this XML file, the ServiceCheckRunner constructor instantiates a logger for each specified logger. Then it instantiates a ServiceCheck object for each specified service.

Note - The constructor uses the Reflection_Class class to introspect the service and logger classes before you try to instantiate them. This is not necessary, but it is a nice demonstration of the new Reflection API in PHP 5. In addition to classes, the Reflection API provides classes for introspecting almost any internal entity (class, method, or function) in PHP.

To use the engine you've built, you still need some wrapper code. The monitor should prohibit you from starting it twice—you don't need double messages for every event. It should also accept some options, including the following:




A location for the engine's configuration file, which defaults to monitor.xml.


The size of the child process pool the engine will allow, which defaults to 5.


A flag to disable the engine from daemonizing. This is useful if you write a debugging ServiceLogger process that outputs information to stdout or stderr.

Here is the finalized monitor script, which parses options, guarantees exclusivity, and runs the service checks:

require_once "Service.inc";
require_once "Console/Getopt.php";
$shortoptions = "n:f:d";
$default_opts = array('n' => 5, 'f' =>
'monitor.xml'); $args = getOptions($default_opts, $shortoptions,
null); $fp = fopen("/tmp/.lockfile", "a"); if(!$fp || !flock($fp, LOCK_EX | LOCK_NB)) { fputs($stderr, "Failed to acquire lock\n"); exit; } if(!$args['d']) { if(pcntl_fork()) { exit; } posix_setsid(); if(pcntl_fork()) { exit; } } fwrite($fp, getmypid()); fflush($fp); $engine = new ServiceCheckRunner($args['f'],
$args['n']); $engine->loop();

Notice that this example uses the custom getOptions() function defined earlier in this chapter to make life simpler regarding parsing options.

After writing an appropriate configuration file, you can start the script as follows:

> ./monitor.php -f /etc/monitor.xml 

This daemonizes and continues monitoring until the machine is shut down or the script is killed.

This script is fairly complex, but there are still some easy improvements that are left as an exercise to the reader:

  • Add a SIGHUP handler that reparses the configuration file so that you can change the configuration without restarting the server.

  • Write a ServiceLogger that logs to a database for persistent data that can be queried.

  • Write a Web front end to provide a nice GUI to the whole monitoring system.

Further Reading

There are not many resources for shell scripting in PHP. Perl has a much longer heritage of being a useful language for administrative tasks. Perl for Systems Administration by David N. Blank-Edelman is a nice text, and the syntax and feature similarity between Perl and PHP make it easy to port the book's Perl examples to PHP.

php|architect, an electronic (and now print as well) periodical, has a good article by Marco Tabini on building interactive terminal-based applications with PHP and the ncurses extension in Volume 1, Issue 12. php|architect is available online at http://www.phparch.com.

Although there is not space to cover it here, PHP-GTK is an interesting project aimed at writing GUI desktop applications in PHP, using the GTK graphics toolkit. Information on PHP-GTK is available at http://gtk.php.net.

A good open-source resource monitoring system is Nagios, available at http://nagios.org. The monitoring script presented in this chapter was inspired by Nagios and designed to allow authoring of all your tests in PHP in an integrated fashion. Also, having your core engine in PHP makes it easy to customize your front end. (Nagios is written in C and is CGI based, making customization difficult.)

>>> More PHP Articles          >>> More By Sams Publishing

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort


- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates


Dev Shed Tutorial Topics: