Getting Real
One of my recent projects involved building the administration interface for a Web hosting company. This interface, primarily targeted at the company’s clients, included the usual goodies - creating and deleting user and FTP accounts, configuring email forwards and spam filters, and viewing traffic statistics. One of the more novel aspects of this project, however, involved providing users with real-time server information - server uptime, memory usage, CPU load, number of concurrent users and so on.
Now, I’d never done something like this before, and I had no idea how to begin obtaining this information “live” from the system. A little research told me all about the /proc filesystem in Linux, and how it contains information on the system state, updated in real time. I played with this a little bit, confirmed that it contained most of the information I needed, and had started writing some code to interface with it when I decided - almost on an impulse - to see if someone had already invented this particular wheel.
Lo and behold, I found patSysinfo, the answer to all my problems (and then some). Flip the page, and let me tell you more…
Plug And Play
patSysinfo is a PHP-based tool designed, in the author’s words, to “ retrieve a lot of information about the system your HTTP server is running on”. Developed by Gerd Schaufelberger, it is freely available for download and is packaged as a single PHP class which can be easily included in your application.
Very simply, patSysinfo provides application developers with a set of APIs that ease the task of reading system information. This information includes the system’s name and IP address, kernel version and CPU specification; it also includes data on the numbers and types of devices connected to the system, and real-time statistics on memory usage. At any given instant, patSysinfo can tell you which processes are running, and how much memory each one is consuming, together with the system’s load average and number of connected users. If the system has built-in hardware sensors, patSysinfo can go even deeper, interfacing with these sensors via the lm_sensors package at http://secure.netroedge.com/~lm78/ to help you monitor the status of your hardware.
Now, there’s nothing very novel or unique about patSysinfo, nor does it do anything you wouldn’t be able to do yourself, given sufficient time and motivation. Its true value lies in its robust implementation of common UNIX commands (like “top”, “ps”, “uptime” and “uname”) in PHP, thereby making it possible to integrate the output of these commands into a Web application with minimal time and fuss. Written as a PHP class, patSysinfo can substantially reduce the amount of time you spend manipulating and reading system data - especially when you have a specialized application like the one I described earlier.
Once caveat, though: patSysinfo only works with Linux systems, as it uses the special Linux /proc filesystem to obtain runtime information on the system’s state. If you were planning to use this class on Windows, you should probably stop reading right now.
Before proceeding further, you should visit the patSysinfo home page at http://www.php-tools.de/ and download a copy of the latest version. The package contains the main class file, documentation outlining the exposed methods and variables, and some example scripts.
What’s In A Name?
Now that the hard sell is over and you’re (hopefully) all set up with patSysinfo, let’s take a simple example to see how it works.
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get hostname
$name = $sys->getHostName();
// get host IP address
$ip = $sys->getHostIp();
// output values
echo "This system is named $name and has IP address $ip";
?>
Here’s the output:
This system is named olympus.local.net and has IP address 192.168.0.2
Let’s dissect this a little to see how it works.
- The first step is, obviously, to include all the relevant files for the class to work.
// include class
include("patSysinfo.php");
Once that’s done, I can safely create an object of the patSysinfo class.
// instantiate object
$sys = new patSysinfo();
This object instance will serve as the central source for all system information, allowing me to do all kinds of nifty things with it.
- Next, the object’s getHostName() and getHostIp() methods are used to obtain the system’s host name and IP address respectively,
// get host name
$name = $sys->getHostName();
// get host IP address
$ip = $sys->getHostIp();
Most of the patSysinfo API calls look like this - the word “get” followed by the information that is required. In the example above, the object first looks up the file “/proc/sys/kernel/hostname” for the current hostname, and then obtains the IP address using the host name and the gethostbyname() PHP function
- Finally, all that’s left is to actually use the data retrieved by the methods - in this case, print it all to the standard output device.
// output values
echo "This system is named $name and has IP address $ip";
Up And At ‘Em
How about finding out how long it’s been since the system’s last reboot? Well, patSysinfo allows you to duplicate the “uptime” command with its getUptime() function. Take a look:
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get uptime
$uptime = $sys->getUptime();
// output values
echo "Last reboot was " . $uptime['days'] . " days, " . $uptime['hours'] . " hours and " . $uptime['mins'] . " minutes ago";
?>
The getUptime() method returns the time since the system’s last reboot as an associative array with keys “days”, “mins” and “hours”. This can then easily be formatted into a readable string, as above. Here’s the output:
Last reboot was 0 days, 1 hours and 43 minutes ago
Want to know a little bit more about the hardware and software running on the system? Take a look at the getKernelVersion() and getCpu() functions, which return the current kernel version and processor details respectively.
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get kernel version
$kv = $sys->getKernelVersion();
// get processor information
$cpuArray = $sys->getCpu();
// extract model, speed, cache etc
$model = $cpuArray[0]['model'];
$speed = $cpuArray[0]['mhz'];
$cache = $cpuArray[0]['cache'];
$mips = $cpuArray[0]['bogomips'];
// output values
echo "Kernel $kv running on a $model at $speed MhZ ($cache cache, $mips bogomips)";
?>
The getCpu() function, in particular, deserves closer attention. This function returns an array, each element of which is itself an associative array representing one of the processors in the CPU (most often, you will have a single-processor CPU and therefore only one element in this array). The associative array for each processor itself contains information on the processor name, clock speed, cache size and other relevant values.
Here’s the output:
Kernel 2.4.20 running on a Pentium III (Katmai) at 451.03 MhZ (512 KB cache, 897.84 bogomips)
Carrying The Load
If it’s system performance you’re interested in, patSysinfo can give you that as well. Consider the getLoadAvg() method, which returns the average CPU load for the last 1, 5 and 15 minutes, or the getNumberUsers() function, which returns the number of users currently logged in to the system.
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get load average
// returns array of 3 values
$loadArray = $sys->getLoadAvg();
// get number of users
$users = $sys->getNumberUser();
// output values
echo "Load averages " . $loadArray[0] . " (1 min) " . $loadArray[1] . " (5 min) " . $loadArray[2] . " (15 min), $users users";
?>
Here’s the output:
Load averages 0.01 (1 min) 2.11 (5 min) 1.43 (15 min), 12 users
You can obtain a list of all running processes with the getProcesses() method, equivalent to the UNIX “ps” command. The list of processes is returned as an array, each element of which represents a running process and contains details on that process’ owner, ID, current status and resource usage. Consider the following example, which illustrates:
<html>
<head>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<td><u>Process ID</u></td>
<td><u>Command</u></td>
<td><u>Owner</u></td>
<td><u>Terminal</u></td>
<td><u>Status</u></td>
<td><u>Start</u></td>
<td><u>Duration</u></td>
<td><u>CPU %</u></td>
<td><u>Memory %</u></td>
</tr>
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get process list
$processes = $sys->getProcesses();
foreach ($processes as $p) {
echo "<tr>";
echo "<td>" . $p[pid] . "</td>";
echo "<td>" . $p[command] . "</td>";
echo "<td>" . $p[user] . "</td>";
echo "<td>" . $p[tty] . "</td>";
echo "<td>" . $p[stat] . "</td>";
echo "<td>" . $p[start] . "</td>";
echo "<td>" . $p[time] . "</td>";
echo "<td>" . $p[cpu] . "</td>";
echo "<td>" . $p[mem] . "</td>";
echo "</tr>";
}
?>
</table>
</body>
</html>
And here’s what the output looks like:
A variant of this is the getTopProcesses() method, which returns the same output as getProcesses() but sorts the data by CPU usage. Here’s the script,
<html>
<head>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<td><u>Process ID</u></td>
<td><u>Command</u></td>
<td><u>Owner</u></td>
<td><u>Terminal</u></td>
<td><u>Status</u></td>
<td><u>Start</u></td>
<td><u>Duration</u></td>
<td><u>CPU %</u></td>
<td><u>Memory %</u></td>
</tr>
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get process list
$processes = $sys->getTopProcesses();
foreach ($processes as $p) {
echo "<tr>";
echo "<td>" . $p['pid'] . "</td>";
echo "<td>" . $p['command'] . "</td>";
echo "<td>" . $p['user'] . "</td>";
echo "<td>" . $p['tty'] . "</td>";
echo "<td>" . $p['stat'] . "</td>";
echo "<td>" . $p['start'] . "</td>";
echo "<td>" . $p['time'] . "</td>";
echo "<td>" . $p['cpu'] . "</td>";
echo "<td>" . $p['mem'] . "</td>";
echo "</tr>";
}
?>
</table>
</body>
</html>
and here’s the output:
For script such as these, which retrieve real-time information from the system, it’s a good idea to insert an auto-refresh header at the top of the page, so that the page automatically updates itself with the latest information at a user-specified interval.
A Nifty Device
The running kernel stores detailed information on all devices connected to the system, and makes this information available via the /proc filesystem. This means that patSysinfo can read it. And read it it does - the class includes three methods designed specifically to provide information on the PCI, IDE and SCSI devices attached to the system. These functions are called getPCIDevs(), getIDEDevs() and getSCSIDevs()respectively, and they’re demonstrated in the following script.
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
?>
<html>
<head>
</head>
<body>
<h2>PCI Devices</h2>
<?php
// get PCI device list
$pci = $sys->getPCIDevs();
// check to see if devices exist
// then print
if (sizeof($pci) > 0) {
echo "<ul>";
foreach ($pci as $p) {
echo "<li>$p";
}
echo "</ul>";
} else {
echo "None";
}
?>
<h2>IDE Devices</h2>
<?php
// get IDE device list
$ide = $sys->getIDEDevs();
// check to see if devices exist, then print
if (sizeof($ide) > 0) {
echo "<ul>";
foreach ($ide as $i) {
$str = join($i, ", ");
echo "<li>$str";
}
echo "</ul>";
} else {
echo "None";
}
?>
</body>
</html>
Here’s what the output might look like:
In a similar manner, patSysinfo also allows you to retrieve detailed data transfer statistics and information on the network interfaces that have been configured for the system. This is done via the getNetDevs() method, demonstrated below:
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get list of networking interfaces
$net = $sys->getNetDevs();
// print data
print_r($net);
?>
The return value of getNetDevs() is a series of arrays containing detailed statistical information about traffic on each network interface. Here’s some sample output:
Array
(
[0] => Array
(
[name] => sum
[rxByte] => 749.06 kByte
[rxPacket] => 6185
[rxErr] => 0
[rxDrop] => 0
[rxFifo] => 0
[rxFrame] => 0
[rxCompressed] => 0
[rxMulticast] => 0
[txByte] => 869.15 kByte
[txPacket] => 5135
[txErr] => 0
[txDrop] => 0
[txFifo] => 0
[txColls] => 0
[txCarrier] => 0
[txCompressed] => 0
)
[1] => Array
(
[name] => eth0
[rxByte] => 749.06 kByte
[rxPacket] => 6185
[rxErr] => 0
[rxDrop] => 0
[rxFifo] => 0
[rxFrame] => 0
[rxCompressed] => 0
[rxMulticast] => 0
[txByte] => 869.15 kByte
[txPacket] => 5135
[txErr] => 0
[txDrop] => 0
[txFifo] => 0
[txColls] => 0
[txCarrier] => 0
[txCompressed] => 0
)
)
Note that this array does not include the local loopback, and that patSysinfo adds a virtual interface named “sum” which contains summary totals.
Running Out Of RAM
Detailed memory usage can be obtained via the very cool getMem() method, which provides data on current memory usage and available resources. Take a look:
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get memory information
$mem = $sys->getMem();
// print data
print_r($mem);
?>
Here’s the output:
Array
(
[0] => Array
(
[type] => mem
[total] => 123.73 MByte
[used] => 36.02 MByte
[free] => 87.71 MByte
[shared] => 0.00 Byte
[buffers] => 1.56 MByte
[cached] => 22.25 MByte
[percent] => 10
)
[1] => Array
(
[type] => swap
[total] => 0.00 Byte
[used] => 0.00 Byte
[free] => 0.00 Byte
[shared] => NA
[buffers] => NA
[cached] => NA
[percent] => 0
)
)
This usually looks a lot nicer when it’s properly formatted into an HTML table, as in this revision of the script above:
<html>
<head>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<td><u>Type</u></td>
<td><u>Total memory</u></td>
<td><u>Used memory</u></td>
<td><u>Free memory</u></td>
<td><u>Shared</u></td>
<td><u>Buffers</u></td>
<td><u>Cached</u></td>
</tr>
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get memory information
$mem = $sys->getMem();
// output memory information
foreach ($mem as $m) {
echo "<tr>";
echo "<td>" . $m['type'] . "</td>";
echo "<td>" . $m['total'] . "</td>";
echo "<td>" . $m['used'] . "</td>";
echo "<td>" . $m['free'] . "</td>";
echo "<td>" . $m['shared'] . "</td>";
echo "<td>" . $m['buffers'] . "</td>";
echo "<td>" . $m['cached'] . "</td>";
echo "</tr>";
}
?>
</body>
</html>
And here’s the output:
Mounting Up
Finally, you can obtain information on mounted file system with the getMounts() method, which returns an array containing detailed information from both the “df” command and “/proc/mounts”. Take a look:
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get mounted file systems
$mounts = $sys->getMount();
// output mount information
print_r($mounts); die;
?>
Here’s what the output of this script might look like:
Array
(
[0] => Array
(
[disk] => /dev/hda3
[size] => 4.73 GByte
[used] => 923.00 MByte
[free] => 3.59 GByte
[percent] => 21
[mount] => /
[type] => ext2
)
[1] => Array
(
[disk] => /dev/hda2
[size] => 4.89 GByte
[used] => 346.95 MByte
[free] => 4.55 GByte
[percent] => 7
[mount] => /mnt/dos
[type] => vfat
)
[2] => Array
(
[disk] => /dev/hda4
[size] => 15.64 MByte
[used] => 1.79 MByte
[free] => 13.85 MByte
[percent] => 12
[mount] => /mnt/scamp
[type] => msdos
)
)
Of course, this isn’t very useful by itself - what you really need to do is format it into a tabular representation, like this:
<html>
<head>
</head>
<body>
<table border="1" cellspacing="0" cellpadding="5">
<tr>
<td><u>Disk</u></td>
<td><u>Mount point</u></td>
<td><u>Type</u></td>
<td><u>Size</u></td>
<td><u>Used space</u></td>
<td><u>Free space</u></td>
<td><u>Used space %</u></td>
</tr>
<?php
// include class
include("patSysinfo.php");
// instantiate object
$sys = new patSysinfo();
// get mounted file systems
$mounts = $sys->getMount();
// output mount information
foreach ($mounts as $m) {
echo "<tr>";
echo "<td>" . $m['disk'] . "</td>";
echo "<td>" . $m['mount'] . "</td>";
echo "<td>" . $m['type'] . "</td>";
echo "<td>" . $m['size'] . "</td>";
echo "<td>" . $m['used'] . "</td>";
echo "<td>" . $m['free'] . "</td>";
echo "<td>" . $m['percent'] . " %</td>";
echo "</tr>";
}
?>
</body>
</html>
Here’s the (much-friendlier) output:
Link Zone
That’s about it for the moment. In this article, I introduced you to the patSysinfo class, which is designed primarily to assist you in the reading of real-time system information on a Linux system. I showed you how to use built-in class methods to retrieve the system’s uptime, load average, host name and IP address, and how to obtain the kernel version and CPU speed. I also showed you to how to retrieve real-time information on memory usage, running processes and the list of processes using the most CPU power. Finally, I wrapped things up with a look at the functions that retrieve the list of devices attached to the system, and the list of mounted file systems.
If you’d like to learn more about patSysinfo and its related tools, you should take a look at the following links:
The official patSysinfo Web site, at http://www.php-tools.de/
The lm_sensors package for hardware monitoring, at http://secure.netroedge.com/~lm78/
Till next time…ciao!
Note: All examples in this article have been tested on Linux/i586 with PHP 5.0, Apache 1.3.23 and patSysinfo 1.7. Examples are illustrative only, and are not meant for a production environment. Melonfire provides no warranties or support for the source code described in this article. YMMV!
Note: Examples are illustrative only, and are not meant for a production environment. Melonfire provides no warranties or support for the source code described in this article. YMMV!
This article was first published on 16 Dec 2003.