LoadMon: Web Server Graphical Load Indicator
by Jay D. Dyson <jdyson@treachery.net>
FOREWORD:
I have been approached several times regarding the "Current Load" indicator that's
displayed at the bottom left-hand side of the main page of Treachery Unlimited.
In the time that this load display has been up, I've received a number of inquiries which
boil down to two basic questions:
- Is that a real system load indicator, or is it just a mock-up?
- Will you release the source code?
In answer to these questions: yes, it is a real load indicator; and yes, I will release
the source code. In fact, the utility is really quite simple and the commenting in the PERL code makes it
rather self-explanatory, so this web page is the only documentation I'll write for it.
This software is released under the terms and conditions of the
Gnu Public License (GPL).
I wrote it, and I'd appreciate credit for it. That's all.
DOWNLOADING THIS SCRIPT:
|
loadmon-1.2.tar.gz |
|
SHA1 Hash: |
c4cdb3c925d3d2029274c616acdfea44a4601fd6 |
|
MD5 Hash: |
4542cebb6b3924db889cdea51dca5f07 |
PURPOSE OF THIS SCRIPT:
This script was authored as a remote diagnostic tool to rule out system resource starvation in the
event of slow web server response. By ruling out system load as a factor, I was able to focus my investigation on
network conditions which could account for any server response lag. This was particularly useful when I was in a
location or situation in which I could not securely log in to the web server in question.
Side note: While the images associated with this script will need to be placed somewhere in the document
root of your web server, this script can be installed anywhere on your system.
ROLE OF THIS SCRIPT:
This script is not a CGI script! This script is a continually-running program that is initiated by
the user (or via system startup scripts) and runs in the background. What this script does is generate HTMLized output
at defined intervals set in the script itself. The HTMLized output file can then be incorporated into a selected web
page (or pages) using the Server Side Include "include file" directive.
This script was designed with UNIX systems in mind. Since Microsoft Windows does not have a native equivalent
to UNIX uptime(1) , it's unlikely this script can ever be adapted for any PERL variant used on Windows. But hey, things
change. Maybe someday...
THE SCRIPT, WITH COMMENTARY:
The script opens with all the standard comments, but take special notice to the requirements
listed here (PERL version, SSI enabled on the web server, and images). If you are unfamiliar with how to
enable Server-Side Includes (SSI)
on your web server, consult your web server's documentation.
Depending on your OS, PERL may be located somewhere other than /usr/local/bin .
Do a 'which perl ' at the command line to determine PERL's location on your system and modify this script
accordingly.
#!/usr/local/bin/perl -T
#
# LOADMON : Graphical system load display for web pages.
# AUTHOR : Jay D. Dyson <jdyson@treachery.net>
# VERSION : 1.2 (Released to public - 09/08/2002)
# REQUIRES : PERL v5.x or higher; Server-Side Includes
# enabled on web server; nohup execution (or
# inclusion in system startup scripts); and 4
# images (provided with distro tarball).
# LICENSING: Released under GNU Public License (GPL).
# |
First you must define the path and filename where the script can write the parsed uptime report.
You will need to change this path declaration to match the directory used by your own system. The
destination file and directory must be user-writable, so whoever runs this script will need to have
the appropriate write access permissions.
$on="/PATH/TO/WEBDIR/LAST_LOAD_FILENAME";
|
Next is the destination where the script writes the HTMLized output that is the graphical load
display. Like the previous directory and file, this must be writable by the user and must be
readable by the web server (e.g., be in the web server's document directory).
$fn="/PATH/TO/WEBDIR/HTML_OUTPUT_FILENAME";.
|
The following code is comprised of defined HTML and image values. These are the building-blocks
for the HTML output of the load monitor script. Also of note is the clearing of the $PATH
environment variable. This is done to comply with the PERL taint mode (which enhances script security).
$ENV{'PATH'}="";$i1="<img src=\"";
$i2="\" height=10 width=8 alt=\"";
$i3="\:\">"; $i4=".\">";
$i5="$i1"."green_on.jpg"."$i2$i3";
$i6="$i1"."red_on.jpg"."$i2$i3";
$i7="$i1"."greenoff.jpg"."$i2$i4";
$i8="$i1"."redoff.jpg"."$i2$i4";
|
Next is the beginning of the load calculations and graphical representation output assembly.
First we start with an endless loop condition.
Keep in mind that, once this script starts, it will run until it is killed. If you start this
script via an interactive shell, it will be killed if you should logout or hit Ctrl+C. Thus, you will need
to start this script using either nohup(1) like this:
nohup ./loadmon > /dev/null 2>&1 &
...or you'll want to add it to a system start-up script. With Linux and most BSD variants, this
would be /etc/rc.d/rc.local . With Solaris, you can create a start up script that would be
something like /etc/rc2.d/S99loadmon . The contents of your startup script would be similar to
the above command line invocation, only you will need to declare the path to the loadmon script.
The following line resets the "light" counter and sets the first "light" at on (since a
completely unlit string of lights would indicate no system activity, which would be untrue). This line also
defines the location of the uptime binary. If this resides somewhere other than
/usr/bin on your system, you will need to change this value.
$n=0;$ld="$i5";$a=`/usr/bin/uptime`;
|
This next line parses the output from uptime and extracts the load average value
we'll use for the load indicator. Scalar variable reassignments are performed for the purpose of arithmetic
decrements on the load value while preserving the original load number.
$a=~s/(.*)average:\s+//ig;$a=~s/\s+//g;
@b=split(/,/,$a);$l=$b[1];$m=$l;
|
At this time, a file handle is assigned to open and read the load value information previously
written to the "last load" report file.
open(L,"<$on");while(<L>){chomp($_);$o=$_;}close(L);
|
Before proceeding further, the script checks to see if the load has changed since it last wrote
to the "last load" file. If the load value has not changed, there is no need to re-generate the HTML and
the script will go back to sleep. If the load value has changed, then the script will proceed with new
HTML output generation.
The following lines step through the output and decrement the load value data by ten percent
(via the subroutine named 'id') with each pass. A total of 10 rounds occur, since 10 times 10% equals 100%
and the graphical load indicator has 10 "lights."
Following each 10 percent decrement, each resulting positive value is assigned an 'on' image
filename which is appended to the constructed HTML that will be written to the HTML output file. When the
value reaches zero or becomes negative, the 'off' image filename is assigned. When the image assignments
are complete, the value of the original load is assigned a "human" named value so visitors using text-based
browsers (such as Lynx and Links) will also know the current load status.
while($n<6){if($m>0.10){$ld="$ld"."$i5";}
else{$ld="$ld"."$i7";}&id;} # Green images
while($n<9){if($m>0.10){$ld="$ld"."$i6";}
else{$ld="$ld"."$i8";}&id;} # Red images
if($l>0.70){$lv="High";}
elsif(($l<0.71)&&($l>0.29)){
$lv="Moderate";}else{$lv="Nominal";}
|
After the entire HTML conversion is completed, the "HTML output" file is written to. File locks
are performed briefly so that any simultaneous web requests will pause for a fraction of a second while the
new load information is written. This prevents incomplete HTML rendering which can skew the visitor's web
page appearance. There is no appreciable lag for the end user since the open, lock, write, and unlock event
occurs within an imperceptible period of time.
open(O,">$fn");flock(O,2);
print O "$ld<br><font size=1>($lv)<font>\n";
flock(O,8);close(O);
|
Once the calculations are complete and the new HTML output has been written, the script closes
the process by updating the numeric load value to the "last load" file.
open(M,">$on");print M "$l\n";close(M);
|
Once all of the above steps have completed, the script sleeps for 60 seconds. You can change
this value to suit your preferences, though it is not recommended that you set the sleep time to less than
30 seconds as this will not yield any appreciable quality in load reporting.
This is the previously-mentioned calculation subroutine. This exists
to avoid redundant code.
} sub id {$m=$m-0.10;$n++;}
|
CLOSING REMARKS:
That's the graphical load monitor script in a nutshell. Please drop me
a line if you find this script useful.
|