Social Media Revolution
by James on Sep.23, 2009, under Intertubes
Funnily enough, a mate posted this on Facebook, and I thought it was awesome, so had to share it!
Kirwans Track
by James on Sep.13, 2009, under Mountain Biking
So on the 11th we got asked if we wanted to go Heli Biking at Kirwans Track just up by Reefton on the 12th. It’s not generally something we had to think about, so an instant yes was given.
Having previously done the Croesus Track by Helicopter and buckling my wheel half way down while trying to overtake a mate while making race car noises (Some people would call that Karma) and having to pretty much walk the rest of the way out, I was pretty keen to make the most of this trip.
The track was pretty awesome, with only minor unridable bits due to logs across the track or wash outs, and only very minor uphill. I managed to destroy my largest chain ring in a minor off I had and replace two rear tubes, but aside from that it was awesome. Would definitely plan to do this again during Summer.
Apache VHost Monitoring with Munin
by James on Sep.10, 2009, under Dev
Alright, must be time for another geek post.
I’m obsessed with stats, anything and everything, if you can report and graph on it, I’m interested. Recently I’ve been experimenting with different server monitoring tools, having mainly been a Cacti user for local networks I wanted to get away from having to rely on a funky perl script via SNMP to get some specific stats on multiple servers from the one location. After much research, Munin seemed to be the most appropriate option, so I gave it a go.
There is a Munin package available for Debian Etch, so installation was simple and it detected what other services I was running and enabled the appropriate plugins for this. This went mostly ok, there were still some bits and pieces left over from Postfix which I was no longer using even though it thought I had, and the Sendmail stats weren’t generating any information. It was easy enough to remove the Postfix plugin, and it turns out the error with Sendmail stats isn’t actually an issue with Munin, it’s just that the plugin for Munin uses the “mailstats” command which doesn’t appear to be configured correctly out of the box for Etch. I won’t go into detail, but if you’re having this issue, the fix is simple and described here.

Example memory usage on one server over nearly 24 hours.
Everything was going pretty smoothy, except Apache monitoring, which was one of the main things I wanted to keep an eye on. The built in Apache stats didn’t work straight out of the box, as they required the server-status module to be loaded along with the libwww-perl package, which I hadn’t done, but even then they were still lacking. I did some searching and found this blog post that looked to display pretty much exactly what I was after. Unfortunately most of the links to software were dead and the ones I found weren’t appropriate for Debian Etch.

Apache Watch example from Freshnet
After a lot of trouble shooting and searching and this very helpful wiki post, I got a completely workable solution. If you’re interested in this, follow the steps below. I haven’t included the actual install/configure of Munin, but this will take care of making sure the default Apache plugins work correctly, along with the extra third party mod_watch and associated apache_watch_ munin plugins.
So first up, to reiterate, if you don’t already have a working Munin, don’t follow these steps. I’m assuming you already have that part done, you’re just having issues with the Apache stats, or want extra Apache stats. If you have a working Munin, continue on:
First up, we need the Apache2 Dev packages to compile the mod_watch plugin from source. Along with this we’ll grab libwww-perl, as we need this to grab the stats.
apt-get install apache2-dev libcrypt-ssleay-perl libwww-perl
Download and extract the apache_watch module. The original website for this software is here, however for what ever reason it is not available from there anymore.
cd /root wget http://rand.stubbedtoe.co.nz/binarys/mod_watch-4.3_apache22_mod.tar.gz tar -xvzf mod_watch-4.3_apache22_mod.tar.gz cd mod_watch-4.3_apache22_mod
Change the Makefile.dso to our needs for Debian Etch
nano Makefile.dso
You should only have to change two things, the APXS location, and STATEDIR:
# The location of apxs utility. # #APXS=/home/apache2/bin/apxs APXS=/usr/bin/apxs2 # # The location of apachectl utility to stop/start/restart targets. # APACHECTL=apache2ctl # # Where the scripts should live # SCRIPTDIR=/usr/local/sbin # # Where to store the weenie files. # STATEDIR=/usr/lib/apache2/modules/mod_watch/ # # Define to use unsigned long long counters. # #BIG=-DUSE_OCTET_COUNTER_64 # # Extras # DEF=$(BIG) -DSTATEDIR='\"$(STATEDIR)\"' INC= LIB= ~~~~~~~~~
Now build the package and copy it to the correct place
make -f Makefile.dso build make -f Makefile.dso install cp mod_watch.c /usr/share/munin/plugins/ chmod 755 /usr/share/munin/plugins/mod_watch.c
Now we need to make Apache2 load the module. There are a few ways to do this, but I wanted to stick with the default way rather than editing the standard apache2.conf. First up we need to create a couple of new files in the mods-available directory.
nano /etc/apache2/mods-available/watch.load
This only needs one line of code:
LoadModule watch_module /usr/lib/apache2/modules/mod_watch.so
Now the conf file. We create this for consistences sake, however I leave everything commented out. This is so we have more control over where this information is going to be displayed, if we didn’t want it on the default website.
nano /etc/apache2/mods-available/watch.conf
And fill it with this:
#<ifmodule mod_watch.c> # Allows the URL used to query virtual host data: # # http://www.snert.com/watch-info # # <location /watch-info> # SetHandler watch-info # Order allow,deny # Allow from 127.0.0.1 # </location> # Intended for debugging and analysis of shared memory # hash table and weenie files: # # http://127.0.0.1/watch-table # # <location /watch-table> # SetHandler watch-table # Order allow,deny # Allow from 127.0.0.1 # </location> # <location /watch-list> # SetHandler watch-list # Order allow,deny # Allow from 127.0.0.1 # </location> #</ifmodule>
We need to comment out the standard .conf files for both server-status and server-info handlers:
nano /etc/apache2/mods-available/status.conf
#<ifmodule mod_status.c> # # Allow server status reports generated by mod_status, # with the URL of http://servername/server-status # Uncomment and change the ".example.com" to allow # access from other hosts. # #<location /server-status> # SetHandler server-status # Order deny,allow # Deny from all # Allow from localhost ip6-localhost # Allow from .example.com #</location> #</ifmodule>
And info.conf
nano /etc/apache2/mods-available/info.conf
#<ifmodule mod_info.c> # # Allow remote server configuration reports, with the URL of # http://servername/server-info (requires that mod_info.c be loaded). # Uncomment and change the ".example.com" to allow # access from other hosts. # #<location /server-info> # SetHandler server-info # Order deny,allow # Deny from all # Allow from localhost ip6-localhost # Allow from .example.com #</location> #</ifmodule>
By default all of the Apache related Munin scripts access the information they require via http://localhost/ – You can change this in the configuration of the Munin plugins, but I won’t go into detail here. If you do do this, you’ll have to make sure the appropriate vhost’s config file has the following configuration added to it, but for this example we’ll be adding it to the “default” website in Debian Etch.
nano /etc/apache2/sites-available/default
Add the following code at the very bottom, just above the </VirtualHost>. If you want to view this information from your own computer, replace your.ip.address with your IP. This step is helpful for trouble shooting. Remember to remove it afterwards if you don’t have a static IP address, or if it is largely shared.
#Munin Stats
<ifmodule mod_status.c>
<location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from 127.0.0.1 your.ip.address
</location>
</ifmodule>
<ifmodule mod_info.c>
<location /server-info>
SetHandler server-info
Order deny,allow
Deny from all
Allow from 127.0.0.1 your.ip.address
</location>
</ifmodule>
<ifmodule mod_watch.c>
<location /watch-info>
SetHandler watch-info
Order deny,allow
Deny from all
Allow from 127.0.0.1 your.ip.address
</location>
<location /watch-table>
SetHandler watch-table
Order deny,allow
Deny from all
Allow from 127.0.0.1 your.ip.address
</location>
<location /watch-list>
SetHandler watch-list
Order deny,allow
Deny from all
Allow from 127.0.0.1 your.ip.address
</location>
</ifmodule>
#End Munin Stats
Now we need to enable all the appropriate Apache2 modules, and restart Apache:
a2enmod watch info status /etc/init.d/apache2 restart
If everything has worked, you should be able to execute the following with out wget throwing any 404 or 403 errors. Likewise if you chose to add your IP address, you should be able to access from your web browser, however if the wget still fails, then the plugins will not worth either:
wget http://your.server.ip/server-status wget http://your.server.ip/server-info wget http://your.server.ip/watch-info wget http://your.server.ip/watch-table wget http://your.server.ip/watch-list
If all of those work fine and the pages that are downloaded have content in them, you can proceed to the next step. If they haven’t, double check your config or post a comment and I’ll see if I can help you out.
Now we create the apache_watch_ Munin plugin file.
/usr/share/munin/plugins/apache_watch_
And fill it with this:
#!/usr/bin/perl
#
# Parameters supported:
#
# config
# autoconf
#
# Configurable variables
#
# url - Override default status-url
#
# Must be symlinked to what the graph should monitor. Run with --suggest
# to see valid targets - or just run munin-node-configure --shell
#
# Written by Björn Ruberg 2006-2007
#
# Magic markers:
#%# family=auto
#%# capabilities=autoconf suggest
my $ret = undef;
if (!eval "require LWP::UserAgent;") {
$ret = "LWP::UserAgent not found";
}
# watch-list exists on localhost
# watch-info does not
my %plugs = (
'bytes' => 'Input/output (bytes)',
'requests' => 'Requests',
'documents' => 'Documents served',
);
my $URL = exists $ENV{'url'} ? $ENV{'url'} : "http://localhost:%d/watch-list";
my @PORTS = exists $ENV{'ports'} ? split(' ', $ENV{'ports'}) : (80);
my $type = "throughput";
if (exists $ARGV[0] and $ARGV[0] eq "autoconf") {
if ($ret) {
print "no ($ret)\n";
exit 1;
}
my $ua = LWP::UserAgent->new (timeout => 30);
my @badports;
foreach my $port (@PORTS) {
my $url = sprintf $URL, $port;
my $response = $ua->request (HTTP::Request->new('GET', $url));
push @badports, $port unless $response->is_success;
}
if (@badports) {
print "no (no mod_watch exists on ports @badports)\n";
exit 1;
} else {
print "yes\n";
exit 0;
}
}
if (exists $ARGV[0] and $ARGV[0] eq "suggest") {
while (my ($key, undef) = each %plugs) {
print "$key\n";
}
exit 0;
}
my @servers = ();
my @data;
foreach my $port (@PORTS) {
my $ua = LWP::UserAgent->new (timeout => 30);
my $url = sprintf $URL, $port;
my $response = $ua->request (HTTP::Request->new ('GET', $url));
foreach my $string (split (/\n/, $response->content)) {
my ($server, undef, $ifInOctets, $ifOutOctets, $ifRequests,
$ifDocuments) = split (/\s/, $string, 6);
push @servers, $server unless $server eq "SERVER";
push @data, "$server $ifInOctets $ifOutOctets $ifRequests $ifDocuments"
unless $server eq "SERVER";
}
}
# From here and out, the plugin must be run with a symlinked service.
my $check = join ("|", keys %plugs);
die ("Plugin must be symlinked to aspect to be monitored")
unless $0 =~ /\_($check)$/;
my $action = $1;
if (exists $ARGV[0] and $ARGV[0] eq "config") {
print "graph_title Apache $plugs{$action}\n";
print "graph_args --base 1000 -l 0\n";
print "graph_category apache\n";
print "graph_vlabel activity\n";
my $i = 0;
foreach my $server (sort (@servers)) {
(my $txtserver = $server) =~ s/(-|\.)/\_/g;
my $draw = ($i==0) ? 'AREA' : 'STACK';
if ($action eq "bytes") {
print "${txtserver}.label $server\n";
print "${txtserver}.draw $draw\n";
print "${txtserver}.type COUNTER\n";
} else {
print "${txtserver}.label $server\n";
print "${txtserver}.draw $draw\n";
print "${txtserver}.type COUNTER\n";
}
$i++;
}
exit 0;
}
foreach my $string (sort (@data)) {
my ($server, $ifInOctets, $ifOutOctets, $ifRequests, $ifDocuments) =
split (/\s/, $string);
(my $txtserver = $server) =~ s/(-|\.)/\_/g;
if ($action eq "documents") {
print "${txtserver}.value $ifDocuments\n";
} elsif ($action eq "requests") {
print "${txtserver}.value $ifRequests\n";
} elsif ($action eq "bytes") {
print "${txtserver}.value " . ($ifInOctets + $ifOutOctets) . "\n";
}
}
Now we just need to do some chmod, create some symlinks, restart Munin and we’re there!
chmod 755 /usr/share/munin/plugins/apache_watch_ ln -s /usr/share/munin/plugins/apache_watch_ /etc/munin/plugins/apache_watch_bytes ln -s /usr/share/munin/plugins/apache_watch_ /etc/munin/plugins/apache_watch_documents ln -s /usr/share/munin/plugins/apache_watch_ /etc/munin/plugins/apache_watch_requests cd /usr/share/munin/plugins/ ./apache_watch_ autoconf
If the last command returns “yes.” – Then you are safe to restart Munin and config the individual stats.
/etc/init.d/munin-node restart cd /usr/share/munin/plugins/ munin-run apache_watch_bytes config munin-run apache_watch_documents config munin-run apache_watch_requests config
You should now start seeing Apache VHost graphs propagate in your Munin stats.
The Motorcycle Follies
by James on Aug.17, 2009, under Motorbikes
So I got my Motorbike Licence, surely this will only speed up the chances of an explosive death, but hey, it’s all in good fun eh? The main point of this post is to do with mucking around with a GPX veiwer for future JetSki/MTB adventures, so getting straight to the point:
Seems to work pretty well. Created using this plugin here. I’d also experimented with GPX Flash which is the same, but Flash based. Had a few problems though, mainly the developer is German, and the English translation doesn’t seem work on the Flash file, secondly it didn’t work out speed, where this one does.
Vimeo > YouTube
by James on Mar.25, 2009, under Mountain Biking
So I’ve made a couple more proper vids now, one of Charming Creek, and one of Cape Foulwind Walkway. I still have a bit more tweaking to do, and I really need to mount the camera on the handle bars.
Also, I can’t beleive how much awesomer Vimeo’s interface is compared to Youtube. Hopefully they’re going to be around for a long time to come, cause their site is awesome.
Cape Foulwind:
Pretty quick vid, a blast around the Seal Colony. Can’t get to extreme as a lot of tourists.
Charming Creek:
Long, admittantly boring vid. Needs more cowbell/action. Cool tunnel shots though. They actually were that dark, that’s not just the camera :P
GoPro Helmet Hero – The Tests
by James on Mar.16, 2009, under Mountain Biking
So after much stuffing around over the space of a couple of years, I finally purchased a Helmet Cam, the GoPro Motorsports HERO Expansion off TradeMe.
All and all, pretty much what I expected. Not the best video/sound quality in the world, but I’ll take it places I wouldn’t take a thousand+ dollar camera.
Here’s a couple of clips I’ve made. First one was a thrash through the Millenium Walkway with the camera on my helmet, where half way through I realised I hadn’t started the recording yet, and I also had it pointed down too much:
Second one was with it mounted as far back as possible on the bike, again, I didn’t realise my leg would be in the way, heh. I think tomorrow I’ll go for on the handle bars somehow:
Very awesome piece of kit, now I just need to get my JetSki working so I can test it in the River/Ocean
Nine Inch Nails – Auckland ‘09
by James on Mar.08, 2009, under Out and About
Nine Inch Nails/Trent Reznor would be my current all time favourite Band/Person at the moment, so when found out they were having a concert in New Zealand, there was no way in hell I was missing out. They’ve since played in Auckland, and there have been some HD videos stuck up online from their Aussie concerts.
Below is The Fragile, my favourite NIN song.
You can find more of their offical HD vids here: Nine Inch Nails on Vimeo.
Christmas Morning
by James on Dec.25, 2008, under Intertubes
Merry Christmas everyone :D
The Daily English Show
by James on Dec.22, 2008, under Laptop Theft
So, it’s nearly Christmas. Most of the staff are away, and I’ve been looking at doing a redesign for our company website. In amongst all of that I was Googling for certain code snippets and the like, and found myself stuck in one of those chain reaction procrastination loops. I had come across a page in someones signature on a forum, and naturally stuck in the URL for stubbedtoe. While most of the information that came out of it I already knew about, one thing i hadn’t tried before was searching google for the full url to see what random sites had mentioned this blog.
Again, while most of the results were to be expected (Embedded Google Videos of Mr Bliss being a theif) one of them caught my eye above the rest.
I don’t quite know how I didn’t come across this at the start! Fantastic bit of journalism anyhow.
Custom PHP 404 Error Page with Logging
by James on Dec.18, 2008, under Dev
So recently I moved webhosts, and decided to setup some subdomains for my gallery and random shit, rather than just have sub directories so I can get better individual reports. At the time I didn’t think that this would have an impact on things except the images I had hotlinked on a few forums out of my gallery, which I didn’t particularly care about. The short story, I was wrong.
One day I was checking the error logs while I was debugging a script I was writing, and noticed a heck of a lot of 404 errors. I started looking through them all and was a bit shocked. There were so many search engines linking to files that I didn’t even think anyone would care about, and a lot of random people linking to a lot of random images.
It’s an absolute nightmare to get an overall picture of what is going on from the server error log, so I ended up making a custom php error page that would email me when a 404 error happened, then one day after work I came home and had 400 emails, so I changed it to log to MySQL instead, and wrote another page to give me a decent overview of that information.
There are four pieces to this setup, and you’ll require access to your .htaccess file. Put error.php into your root directory, execute the sql to create the database table, make the changes to the .htaccess file and you’re away! Stick errorlog.php where ever you want, and check it every now and then.
error.php – This is the main page that is displayed to the user, and logs the information.
Be sure to change the $database array information if you plan to use MySQL logging.
< ?php
ob_start();
$notification = 'sql'; //If you would rather have this emailed to you, change this to 'email'
$email_to = 'you@domain.co.nz'; //Change this to where you want it sent
$email_from = 'webmaster@domain.co.nz'; //Change this to the reply address
$email_sub = 'Web Error'; //Start of the subject line
error_reporting(0);
/*
We don't want the end user to see any php related errors, ie,
can not connect to database. As this shouldn't happen that
often, it's not really an issue. For testing of this script
however, you should change the above line from 0 to E_ALL
*/
//Database Configuration
$database = array(
"server" => "localhost",
"username" => "localuser",
"password" => "localpass",
"database" => "localbase",
);
$errors = array( //All of these were taken from http://www.askapache.com/wordpress/wordpress-404.html
'400' => array('Bad Request','Your browser sent a request that this server could not understand.'),
'401' => array('Authorization Required', 'This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn\'t understand how to supply the credentials required.'),
'402' => array('Payment Required','INTERROR'),
'403' => array('Forbidden','You don\'t have permission to access THEREQUESTURI on this server.'),
'404' => array('Not Found', 'We couldn\'t find <acronym title="THEREQUESTURI">that uri</acronym> on our server, though it\'s most certainly not your fault.'),
'405' => array('Method Not Allowed', 'The requested method THEREQMETH is not allowed for the URL THEREQUESTURI.'),
'406' => array('Not Acceptable', 'An appropriate representation of the requested resource THEREQUESTURI could not be found on this server.'),
'407' => array('Proxy Authentication Required', 'This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn\'t understand how to supply the credentials required.'),
'408' => array('Request Time-out', 'Server timeout waiting for the HTTP request from the client.'),
'409' => array('Conflict', 'INTERROR'),
'410' => array('Gone', 'The requested resourceTHEREQUESTURIis no longer available on this server and there is no forwarding address. Please remove all references to this resource.'),
'411' => array('Length Required', 'A request of the requested method GET requires a valid Content-length.'),
'412' => array('Precondition Failed', 'The precondition on the request for the URL THEREQUESTURI evaluated to false.'),
'413' => array('Request Entity Too Large', 'The requested resource THEREQUESTURI does not allow request data with GET requests, or the amount of data provided in the request exceeds the capacity limit.'),
'414' => array('Request-URI Too Large', 'The requested URL\'s length exceeds the capacity limit for this server.'),
'415' => array('Unsupported Media Type', 'The supplied request data is not in a format acceptable for processing by this resource.'),
'416' => array('Requested Range Not Satisfiable', ''),
'417' => array('Expectation Failed', 'The expectation given in the Expect request-header field could not be met by this server. The client sent <code>Expect:</code>'),
'422' => array('Unprocessable Entity', 'The server understands the media type of the request entity, but was unable to process the contained instructions.'),
'423' => array('Locked', 'The requested resource is currently locked. The lock must be released or proper identification given before the method can be applied.'),
'424' => array('Failed Dependency', 'The method could not be performed on the resource because the requested action depended on another action and that other action failed.'),
'425' => array('No code', 'INTERROR'),
'426' => array('Upgrade Required', 'The requested resource can only be retrieved using SSL. The server is willing to upgrade the current connection to SSL, but your client doesn\'t support it. Either upgrade your client, or try requesting the page using https://'),
'500' => array('Internal Server Error', 'INTERROR'),
'501' => array('Method Not Implemented', 'GET to THEREQUESTURI not supported.'),
'502' => array('Bad Gateway', 'The proxy server received an invalid response from an upstream server.'),
'503' => array('Service Temporarily Unavailable', 'The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.'),
'504' => array('Gateway Time-out', 'The proxy server did not receive a timely response from the upstream server.'),
'505' => array('HTTP Version Not Supported', 'INTERROR'),
'506' => array('Variant Also Negotiates', 'A variant for the requested resource <code>THEREQUESTURI</code> is itself a negotiable resource. This indicates a configuration error.'),
'507' => array('Insufficient Storage', 'The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request. There is insufficient free space left in your storage allocation.'),
'510' => array('Not Extended', 'A mandatory extension policy in the request is not accepted by the server for this resource.')
);
$cur_err_uri = $_SERVER['REQUEST_URI'];
$cur_err_ref = $_SERVER['HTTP_REFERER'];
$cur_err_code = $_SERVER['REDIRECT_STATUS'];
$cur_err_short = $errors[$cur_err_code][0];
$cur_err_long = str_replace("THEREQUESTURI", $cur_err_uri, $errors[$cur_err_code][1]);
header("HTTP/1.0 $cur_err_code $cur_err_short");
//If you don't output the correct header error, search engines will just assume that the content has changed.
?>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Error - < ?php echo $cur_err_code?></title>
<style type="text/css">
<!--
body {
font-family: Calibri, Tahoma, Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
}
-->
</style>
</head>
<body>
<h1>< ?php echo $cur_err_code?></h1>
<h2>< ?php echo $cur_err_short?></h2>
<p>< ?php echo $cur_err_long?></p>
<p><a href="http://<?php echo $_SERVER['HTTP_HOST']?>" target="_top">Home</a>
< ?php
if ($cur_err_ref != '') {
echo " | <a href=\"$cur_err_ref\" target=\"_top\">Back";
}
?>
</p>
</body>
</html>
< ?php
ob_end_flush();
if ($notification === 'email') { //Email
$email_sub = "$email_sub: $cur_err_code";
$email_msg = "Time: " . date("F j, Y, g:i:s a") . "\r\n";
$email_msg .= "Error: $cur_err_code, $cur_err_short\r\n";
$email_msg .= "Requested: " . $_SERVER['HTTP_HOST'] . " - $cur_err_uri \r\nReferred: $cur_err_ref\r\n";
$email_msg .= "Remote_Addr: " . $_SERVER['REMOTE_ADDR'] . " \r\nBrowser: " . $_SERVER['HTTP_USER_AGENT'] . "\r\n";
$email_head = "From: $email_from\r\nReply-To: $email_from\r\nX-Mailer: PHP/" . phpversion();
mail($email_to, $email_sub, $email_msg, $email_head);
} elseif ($notification === 'sql') { //SQL
$link = mysql_connect($database['server'], $database['username'], $database['password']);
mysql_select_db($database['database'], $link);
include('/home/stubbedt/www/shell/hair.php');
$mysql_query = sprintf("INSERT INTO `m_error` (`id` ,`time` ,`err_code` ,`err_desc` ,`page` ,`refer` ,`remote_addr` ,`browser`) VALUES (NULL , UNIX_TIMESTAMP() , '%s', '%s', '%s', '%s', '%s', '%s');",
mysql_real_escape_string($cur_err_code),
mysql_real_escape_string($cur_err_short),
mysql_real_escape_string($_SERVER['HTTP_HOST'] . $cur_err_uri),
mysql_real_escape_string($cur_err_ref),
mysql_real_escape_string($_SERVER['REMOTE_ADDR']),
mysql_real_escape_string($_SERVER['HTTP_USER_AGENT']));
mysql_query($mysql_query);
mysql_close($link);
}
?>
error.sql – This is the database table setup.
Be sure to change the `localtable` to what you want to use.
CREATE TABLE IF NOT EXISTS `m_error` ( `id` int(8) NOT NULL auto_increment, `time` int(10) NOT NULL, `err_code` int(3) NOT NULL, `err_desc` varchar(100) NOT NULL, `page` varchar(255) NOT NULL, `refer` varchar(255) NOT NULL, `remote_addr` varchar(25) NOT NULL, `browser` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
.htaccess – These are the edits you have to make.
You can put as many or as little errors in here that you want, but the below five are the most common.
#Error Docs ErrorDocument 400 /error.php?e=400 ErrorDocument 401 /error.php?e=401 ErrorDocument 403 /error.php?e=403 ErrorDocument 404 /error.php?e=404 ErrorDocument 500 /error.php?e=500
errorlog.php – This is a crude display of the errors that are being logged.
Again, be sure to change the $database array information if you plan to use MySQL logging.
< ?php
error_reporting(E_ALL); //To surpress erros, change from E_ALL to 0
//Database Configuration
$database = array(
"server" => "localhost",
"username" => "localuser",
"password" => "localpass",
"database" => "localbase",
);
$link = mysql_connect($database['server'], $database['username'], $database['password']);
mysql_select_db($database['database'], $link);
?>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Error - 404</title>
<style type="text/css">
<!--
a {
color: #000000;
text-decoration: none;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
}
acronym {
color: #000000;
text-decoration: none;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
}
body {
font-family: Calibri, Tahoma, Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
}
td.lfb {
border-left-width: thin;
border-left-style: dotted;
border-left-color: #CCCCCC;
}
td.lfb-d {
border-left-width: thin;
border-left-style: dotted;
border-left-color: #999999;
}
td.bmb {
border-bottom-width: thin;
border-bottom-style: dotted;
border-bottom-color: #CCCCCC;
}
td.bmb-d {
border-bottom-width: thin;
border-bottom-style: dotted;
border-bottom-color: #999999;
}
-->
</style>
</head>
<body>
<h1>Error Log</h1>
<h2>Past 10 errors</h2>
<table border="0" cellspacing="1" cellpadding="2">
<tr>
<td class='lfb-d bmb-d'><b>time</b></td>
<td class='lfb-d bmb-d'><b>err_code</b></td>
<td class='lfb-d bmb-d'><b>err_desc</b></td>
<td class='lfb-d bmb-d'><b>page</b></td>
<td class='lfb-d bmb-d'><b>browser</b></td>
<td class='lfb-d bmb-d'><b>remote_addr</b></td>
<td class='lfb-d bmb-d'><b>refer</b></td>
</tr>
< ?php
$mysql_query = "SELECT * FROM `m_error` ORDER BY time DESC LIMIT 0,50;";
$mysql_result = mysql_query($mysql_query);
while ($mysql_row = mysql_fetch_assoc($mysql_result)) {
?>
<tr>
<td class='lfb bmb'>< ?php echo date("d.m.y - H:i:s", $mysql_row['time']); ?></td>
<td class='lfb bmb'>< ?php echo $mysql_row['err_code']; ?></td>
<td class='lfb bmb'>< ?php echo $mysql_row['err_desc']; ?></td>
<td class='lfb bmb'>< ?php echo "<a title=\"http://". $mysql_row['page'] ."\" href=\"http://". $mysql_row['page'] ."\">". substr($mysql_row['page'], 0, 50) .""; ?></td>
<td class='lfb bmb'>< ?php echo "<acronym title=\"". $mysql_row['browser'] ."\">". substr($mysql_row['browser'], 0, 35) .""; ?></td>
<td class='lfb bmb'>< ?php echo $mysql_row['remote_addr']; ?></td>
<td class='lfb bmb'>< ?php echo "<a title=\"http://". $mysql_row['refer'] ."\" href=\"http://". $mysql_row['refer'] ."\">". substr($mysql_row['refer'], 0, 50) .""; ?></td>
</tr>
< ?php
}
?>
</table>
<p>&amp;amp;amp;nbsp;</p>
<h2>Amount of errors, per referer</h2>
<table border="0" cellspacing="1" cellpadding="2">
<tr>
<td class='lfb-d bmb-d'><b>refer_count</b></td>
<td class='lfb-d bmb-d'><b>refer</b></td>
<td class='lfb-d bmb-d'><b>page</b></td>
</tr>
< ?php
$mysql_query = "SELECT count('refer') AS refer_count, refer, page FROM `m_error` GROUP BY refer ORDER BY count('refer') DESC LIMIT 0,50;";
$mysql_result = mysql_query($mysql_query);
while ($mysql_row = mysql_fetch_assoc($mysql_result)) {
?>
<tr>
<td class='lfb bmb'>< ?php echo $mysql_row['refer_count']; ?></td>
<td class='lfb bmb'>< ?php echo "<a title=\"http://". $mysql_row['refer'] ."\" href=\"http://". $mysql_row['refer'] ."\">". substr($mysql_row['refer'], 0, 50) .""; ?></td>
<td class='lfb bmb'>< ?php echo "<a title=\"http://". $mysql_row['page'] ."\" href=\"http://". $mysql_row['page'] ."\">". substr($mysql_row['page'], 0, 50) .""; ?></td>
</tr>
< ?php
}
?>
</table>
<h2>Amount of errors, per page</h2>
<table border="0" cellspacing="1" cellpadding="2">
<tr>
<td class='lfb-d bmb-d'><b>page_count</b></td>
<td class='lfb-d bmb-d'><b>page</b></td>
<td class='lfb-d bmb-d'><b>err_code</b></td>
</tr>
< ?php
$mysql_query = "SELECT count('page') AS page_count, page, err_code FROM `m_error` GROUP BY page ORDER BY count('page') DESC LIMIT 0,50";
$mysql_result = mysql_query($mysql_query);
while ($mysql_row = mysql_fetch_assoc($mysql_result)) {
?>
<tr>
<td class='lfb bmb'>< ?php echo $mysql_row['page_count']; ?></td>
<td class='lfb bmb'>< ?php echo "<a title=\"http://". $mysql_row['page'] ."\" href=\"http://". $mysql_row['page'] ."\">". substr($mysql_row['page'], 0, 50) .""; ?></td>
<td class='lfb bmb'>< ?php echo $mysql_row['err_code']; ?></td>
</tr>
< ?php
}
?>
</table>
<h2>Amount of errors, per browser</h2>
<table border="0" cellspacing="1" cellpadding="2">
<tr>
<td class='lfb-d bmb-d'><b>browser_count</b></td>
<td class='lfb-d bmb-d'><b>browser</b></td>
</tr>
< ?php
$mysql_query = "SELECT count('browser') AS browser_count, browser FROM `m_error` GROUP BY browser ORDER BY count('browser') DESC LIMIT 0,50";
$mysql_result = mysql_query($mysql_query);
while ($mysql_row = mysql_fetch_assoc($mysql_result)) {
?>
<tr>
<td class='lfb bmb'>< ?php echo $mysql_row['browser_count']; ?></td>
<td class='lfb bmb'>< ?php echo "<acronym title=\"". $mysql_row['browser'] ."\">". substr($mysql_row['browser'], 0, 100) .""; ?></td>
</tr>
< ?php
}
?>
</table>
<p>&amp;amp;amp;nbsp;</p>
<p><a href="http://www.stubbedtoe.co.nz" target="_top">Home</a>
</p>
</body>
</html>
< ?php
mysql_close($link);
?>
And there you have it.