http error log reader idea

When PHP throws a wobbly, it usually posts something useful to the Apache error log (usually at /var/log/httpd/error_log), which is nice, but you really want it in your face so you’ll actually do something about it.

I’m not sure if this application already exists, but it would be very handy.

What I want is an application which checks the error log every ten minutes or so, and adds anything new to a bug tracker such as Mantis, which the developer (me) would be using for daily work anyway.

Has anyone seen anything like this already, or should I write it?

Some more precise features:

  • Should work with multiple error logs.
  • Should work over the Net, as those error logs may be on separate machines. To manage this, run separate instances of the reader on those machines, and use a SOAP API (or other RPC) to connect to Mantis.
  • Should create issues referencing the IP address, filename, and line number. If there are multiple errors which reference the same, they should be added as comments to that issue.
  • If an issue is marked as resolved or closed, but another error comes in referencing the same details, the issue should be re-opened with a note explaining that it’s not yet resolved.
  • Other types of errors should be appropriately issued as well, with an “unknown type of issue” error for anything unexpected.

This all sounds so specific that I might just have to write the damned thing. But once it’s done, it should be useful to someone.

writing a plugin for WebME

The core WebME engine doesn’t include Panels functionality, so I’ll use that as the example for the plugin tutorial.

In web design, a Panel is used to display information in a certain location in the layout which should not change throughout the site. For example, you could consider a footer section, sidebar section, or even header section to be a panel. You would want the same information to appear on all pages in that location, but sometimes you might want to change the contents of that panel.

To accomplish this, three things will be needed:

  • A Smarty function to show the plugin in the template. For example, {PANEL name='footer'} or {PANEL name='address'}
  • An admin page to handle the creation/editing of panels.
  • A database table to contain the panel information.

Make sure the ww.plugins directory exists in the root of your WebME and create a subdirectory in it named after the plugin. In this case, /ww.plugins/panels.

In that directory, create a file named plugin.php containing the following:

<?php
$plugin=array(
  'name'=>'Panels',
  'description'=>'Allows content sections to be displayed throughout the site.',
  'frontend'=>array(
    'template_functions'=>array(
      'PANEL'=>array(
        'function' => 'showPanel'
      )
    )
  )
);
function showPanel($vars){
  return 'in the <em>'.htmlspecialchars($vars['name']).'</em> panel';
}

Now you need to add the panel code to the HTML template. In my case, it was ww.skins/orange/h/_default.html. Add this whereever you want the panel code to appear:

<div class="panel">{PANEL name="testing"}</div>

img1

If you view the front-end of your site, you’ll see it’s blank. That’s because the plugin has not been enabled, so the function PANEL doesn’t yet exist. Unfortunately, Smarty doesn’t appear to allow you do do an “{if function_exists(‘PANEL’)}” block to cater for that eventuality, so just make sure to enable the plugin. Go to your admin area (/ww.admin/), and enable it in Options > Plugins. Now it should render better on the front-end.

Next we need to create the database table. In WebME, database management is done by using version-numbers. When the plugin is loaded, its version number is compared against the last version number the system had for that plugin. If the number is higher, then the file upgrade.php in the plugin directory is run.

In the plugin.php file, add 'version'=>1 to the $plugin array, then create the upgrade.php file:

<?php
require SCRIPTBASE.'ww.incs/db.php';
if($version==0){ // panels table
  dbQuery('CREATE TABLE IF NOT EXISTS `panels` (
    `id` int(11) NOT NULL auto_increment,
    `name` text,
    `body` text,
    PRIMARY KEY  (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8');
  $version=1;
}

$DBVARS[$pname.'|version']=$version;
config_rewrite();

What happens there is that the previous version number is checked, the database is updated to the latest version, and the config is updated with the new version number.

For the admin area, we want to create a new menu item linking to an admin page specifically for panels. To do this, add an admin section to the $plugin array in plugin.php:

  'admin'=>array(
    'menu'=>array(
      'top'=>'Misc'
    )
  )

That creates the top-level menu ‘Misc’ in the admin area, and a link under it called ‘Panels’ (from the ‘name’ entry in the $plugin array).

Clicking that link opens a page which says “The panels plugin does not have an admin page. Please contact the plugin author.”

To correct that, create a /ww.plugins/panels/index.php page to handle it.

<?php
$id=(int)@$_REQUEST['id'];
if(isset($_REQUEST['action'])){
  if($_REQUEST['action']=='Save Panel'){
    $q='name="'.addslashes(@$_REQUEST['name']).'",body="'.addslashes(@$_REQUEST['body']).'"';
    if($id)dbQuery("update panels set $q where id=$id");
    else{
      dbQuery("insert into panels set $q");
      $id=dbOne("select last_insert_id() as id",'id');
    }
  }
  else if($_REQUEST['action']=='delete'){
    dbQuery("delete from panels where id=$id");
    $id=0;
  }
}
$panels=dbAll('select id,name from panels order by name');
echo '<div id="leftmenu">';
foreach($panels as $p){
  echo '<a href="/ww.admin/plugin.php?_plugin=panels&id=',$p['id'],'"';
  if($p['id'] == $id)echo ' class="thispage"';
  echo '>'.htmlspecialchars($p['name']).'</a>';
}
echo '<a href="/ww.admin/plugin.php?_plugin=panels">New Panel</a></div>';
$r=dbRow('select * from panels where id='.$id);
echo '<div id="hasleftmenu"><h2>Panel</h2>';
echo '<form method="post" action="/ww.admin/plugin.php?_plugin=panels"><table style="width:90%">';
echo '<tr><th>Name</th><td><input name="name" value="',htmlspecialchars(@$r['name']),'" /></td></tr>';
echo '<tr><th>Body</th><td>',fckeditor('body',@$r['body']),'</td></tr>';
echo '<tr><th colspan="2"><input type="hidden" name="id" value="',$id,'" />';
echo '<input type="submit" name="action" value="Save Panel" />';
if($id)echo '<a href="/ww.admin/plugin.php?_plugin=panels&id='.$id.'&action=delete" onclick="return confirm(\'are you sure you want to remove this panel?\')" title="delete">[x]</a>';
echo '</th></tr></table></form>';

Right. Now, use the new panel admin to create a panel. I’ve created a panel named “testing” with “hello world” written in it. Then, we need to display it on the front-end.

To do this, just amend the showPanel function in plugin.php to take care of it. Here is the whole plugin.php file again, with all amendments applied:

<?php
$plugin=array(
  'name'=>'Panels',
  'description'=>'Allows content sections to be displayed throughout the site.',
  'admin'=>array(
    'menu'=>array(
      'top'=>'Misc'
    )
  ),
  'frontend'=>array(
    'template_functions'=>array(
      'PANEL'=>array(
        'function' => 'showPanel'
      )
    )
  ),
  'version'=>1
);
function showPanel($vars){
  $p=dbRow('select body from panels where name="'.addslashes(@$vars['name']).'" limit 1');
  if(!count($p)){
    return '<em>error - panel <strong>'.htmlspecialchars(@$vars['name']).'</strong> does not exist.</em>';
  }
  return $p['body'];
}

This plugin is available in the svn repository (svn checkout http://webworks-webme.googlecode.com/svn/ww.plugins/panels).

update on Me

Quick update of what’s happening in the world of Kae.

I’ve been busy recently with a new project in the office, making an ultra-WebME system which can be used by companies who are not web designers, to offer their clients “pre-packaged” websites. I may elaborate on that in a few weeks once the pilot study is out of the way.

I haven’t touched the KFM file manager project in ages, and recently realised that it’s because I’m just not happy with it anymore. It’s monstrously complex now, and just not flexible enough for the changes I want to build into it. So, I’m seriously thinking of rewriting it completely, or building a new file manager project to compete with it.

WebME is progressing quickly. The plugins architecture is damned easy to use, if I do say so myself. So much so that Conor wrote a mailing-list plugin before I even got to announce the plugin system. To try it out, get the Subversion copy of WebME, and also the subversion copy of the existing plugins (svn checkout http://webworks-webme.googlecode.com/svn/ww.plugins/) and create a symbolic link from ‘ww.plugins’ in the root of your WebME installation to the checked-out ww.plugins directory. Then in the /ww.admin section, go to Site Options > Plugins and try some stuff. I’ll be writing a proper tutorial on how to create a plugin. Probably today.

I started learning piano at the beginning of last month and am proud to say that I appear to be learning at a prodigious rate. This is probably because I can already play well on a number of other instruments. Last tune I learned was Ecossaise in E Flat by Beethoven (WoO 86), played here by Matt Baker:

Before that was I’ll Take You Home Kathleen, played here by Dave Seddon on steel guitar (couldn’t find a piano version that wasn’t ruined by people singing over the music 😉 ):

I’m still in quite a lot of pain since last week’s operation, but hopefully it will ease off over the weekend, as I have the next chapter of my book to submit.

ie8 finally usable for js debugging

from the IE blog.

The one that I am most pleased about is this one:

It has long been an annoying fact that, despite that fact that most modern web-pages will include multiple JavaScript files, IE would only ever say “error on line n“, with no indication of what JS file was being talked about.

My guess is that IE would internally append/insert the script to the document source itself and would give a number based on that single file.

Based on the rest of the article, it looks like the IE team have been examining other browsers, as there’s nothing much new there that I haven’t seen in other browsers already. The debugging application with breakpoints (et al) is available through Firebug, for example.

The third comment on the page is funny: “i just noticed today that this blog is finally script error free thats good!” – obviously they felt the need to try out their shiny new toy 😉

friday and drink

Just a quick reminder to those of you that like a nice relaxing drink on Fridays – this Friday, the Irish government will be making alcohol illegal to sell, by order of the roman catholic church.

And all because some dude died a few thousand years ago.

Get your drink tomorrow.

Fucking stupid law. I mean, not only can’t you drink, but it’s also a holiday, so what are you supposed to do with yourself on that day???

I’ll be heading into the office to relax for a bit, that’s what.

trip to the dentist

I hate travelling.

Yesterday I was due to get three wisdom teeth removed. One was partially sideways, one was slightly overgrown causing occasional cheek biting, and the other was so close to the jaw hinge that it was impossible to clean.

The appointment was at noon, in Newry, which is only about 25 miles east of where I am.

In order to get there in time, I had to catch a bus at twenty to seven from Bus Éireann. which would change half-way to another bus which would finally arrive in Newry about 10.15. The next bus from them would have arrived at 12:15, so I had to get that one.

I got up at 5am, got dressed, the usual, grabbed a book (The Last Master: Passion and Glory – Volume 3, a fictional Beethoven biography by John Suchet) and left.

Got to the bus station at 5 past 6, so had to wait around for 35 minutes. Better early than late.

6:40 came and went, and there was no bus. Finally, I called Bronwyn and asked her to check the journey planner again. Turns out I’d totally misread the times (7:40, not 6:40) so was still an hour early. I got a cup of tea and waited.

At 7:40, I went out and there were two buses there. I went to the first one which said it was going to Dundalk, and asked if I should get that one if I’m going to Newry. He said no, and pulled out of the station.

I asked the other bus, and he said “you should have gotten the Dundalk bus”.

When I asked the receptionist if there was another on the way, she said I could catch the Ulster Bus in a few minutes. It was to change at Armagh to go to Newry.

The bus arrived and I was finally on my way. The bus’s number was 70. In Armagh, there was a wait of about 40 minutes before I got on the second bus, which was also a number 40.

Finally arrived in Newry, still an hour and a bit early, so I searched arround to find the place I was going, and made sure it was okay for me to go get some food and drink before the jaw ripping began.

As I wasn’t going to be sedated, there were no special rules, so I went and got a sandwich and continued with the book.

At 12, I came back, and the operation began. An X-ray was taken of my head, even though one had already been taken months ago, and the dentist explained exactly what was going to happen. She was not going to remove the overgrown tooth in that session, but would remove the other two.

So it began. The first injection of anaesthetic involved three pin-pricks. I don’t like needles. Within a minute or two, the area was numb and she went in with the tools to work on the first tooth, and upper right wisdom tooth.

She poked and pushed with what felt like a small crowbar. There was a *crack* sound which I heard right through my head, and within seconds, the tooth was out. I hadn’t felt any pain at all. If this was how it was going to be, then I didn’t know what all the fuss was about.

The second tooth was going to be a tricky one. Apparently because of how it had grown, and how close it was to the mandibular nerve, the tooth would need to first be cut in two. Otherwise, it would increase the already 10% chance of me getting Parasthesia (damaged nerve, sometimes permanent, causing loss of sensation in lips and tongue. Can cause symptoms such as drooling and constant tongue biting).

Fine – get on with it. The first had been simple. The second can’t be so hard.

The drilling started. Within seconds I had to stop. The area was not fully anaesthetised and it was goddamned painful. i was jabbed a few more times with the needle.

Even after that, there was still pain. The dentist figured that the pain was coming from /inside/ the tooth, so probed around to find the best place to apply more jabbing.

After a while, she was able to continue without me feeling the need to thrash around. In a minute or so, she managed to extract the tooth in two pieces.

I got to keep the upper one (stuck it in my pocket). The lower was in bits.

So anyway – I was advised to go get some soft or liquid sustenance and avoid any hard food. After I had some soup, I went to the bus station to wait for the number 40 back to Armagh. It was 3.15. I hadn’t bothered checking the bus-time-tables because I figured I’d be waiting there anyway, so why bother…

After an hour or so, the 40 arrived and I got on it.

After another hour or so, it pulled into the station. The /same/ station I had gotten on at! It turns out that even though it was the same bus route, at some times during the day, they change it so that it becomes a 2-bus route. I was apparently supposed to get off at one point and switch to another bus, but had not been aware of it.

I had to wait another hour for another 40. Finally arrived in Armagh about 6.30. The guy at the bus station said that the next bus to Monaghan was at about 8pm.

I waited around for a half-hour then gave up and got a taxi home.

All in all, it took me about fourteen hours to leave the house, get some teeth removed, and get back home.

I was asked to come back next month to get the other wisdom tooth removed. I think I’ll leave it a while longer before doing that. The surgery itself was fine, but the trip was a pain.

inline multi-selects

I just came across this project while looking through referers to this site.

Inline multi-selects – the examples show exactly what is meant – what a brilliantly usable way to select options! I’ve never thought of doing anything like that before. It’s human-readable, and much more friendly than the usual selectbox method.

What’s particularly usable about it is that the selected items are presented as an inline list using natural human language (English for example), instead of a long list with some options ticked.

And I was impressed with myself to see that I might have helped influence it, as my own multi-select widget from 4 years back is referenced.

Cool work, bjorsq (you?), and I /know/ that I will be using that one. I can already imagine using it to select what mailinglists I would want to send an email to (my latest PHP&jQuery project – yet to be properly announced)

forum.php.ie

php.ie has a new forum, forum.php.ie.

This is in response to a massive (by our standards) discussion on the PHP User Group’s mailinglist.

The upshot is that I’ve installed a forum, and eventually, we may create a bridge between the forum and the mailinglist so that emails sent to the mailinglist will be added to the forum and vice-versa. Painful to write, possibly, but it could be interesting.

I blame Conor – he started it!