I never thought I’d learn Ajax (or JavaScript)

UPDATE: This software has been released.

COMET

My boss wanted to watch the Apache access logs from a web page. And top, and mytop. My first solution, which worked (and still works) great, was using a simple COMET stream for each feed. Keeping a process open in php means waiting for output, so I learned that it was best to have only one stream per page. I tried using iframes to display all 3 at once, but Firefox seemed to have trouble dealing with more than 2 kept-open http connections in one window. Essentially, it seemed that Firefox was waiting an arbitrary amount of time before sending out the request for the third iframe, no matter what I did.

So, the COMET stream works great (one or two at a time), and I even set it up to use XML configuration files so that new feed capabilities can be added easily. Perhaps I’ll ask my boss if I can share that code.

Ajax

Since showing three streams on a page proved impractical, I decided to delve into asynchronous requests. There was one major disadvantage: keeping track of order. With the COMET stream, I knew each line of output from the stream was equivalent to a new line of output from the system command (i.e. tail). Apache in particular does not log lines that can be uniquely identified. If I send asynchronous ‘tail’ requests, it is very costly to ascertain whether or not I’ve received any of those lines in previous requets, or whether I’ve missed lines altogether. Costly isn’t good when you’re trying to ‘look but not touch’.

mytop and top are also costly, in the scheme of things. The COMET stream for either of those produced a small but visible load on the system. Since there are other, simpler ways to get the same information, I moved over to using vmstat for my cpu and memory info, and MySQL queries for the database info. For the time being, I abandoned individual process info.

Thinking of how I’d keep track of Apache log lines, the best solution I came up with was cat -n /path/to/apache_log | tail — outputting the last few lines of the log with line numbers (under a PHP wrapper). However, that turned out to be a very costly request indeed, using 60ms of processor time compared to 0ms with just plain tail. Rather than write my own tail program, I decided to stick with the COMET stream for the Apache log, in a frame below the system and MySQL panels.

Everything works now. I believe the tool is actually useful, and it puts very little demand on the server. I fell back on global objects in the JavaScript for the Ajax panels, since I couldn’t find another way to manage the data client-side between events, when no function scope exists. I’ve just got a good book that seems to show me how to get around that… I’ll let you know how it goes.

Here’s a screen shot of the tool:

The data tables update once a second until you hit ’stop.’ If you hit ’start’ again, all of the values will reset. The apache log streams essentially in real time. The ‘highest,’ ‘average,’ and ‘first’ values are calculated only on the timespan monitored - that will help the user catch peaks and informally test the performance of the server during the watched period.

The little yellow time box is a mouse-over goodie to let you know when that value occurred if you place the cursor over a value in the ‘highest’ column. The delta symbols under the MySQL highest & average columns indicate that those are the highest & average incremental changes; the highest & average actual values are not useful for running totals.

Another thing I did not succeed in was getting the JavaScript to dynamically use data structures from different feeds. Trying to define undeclared properties of a global object within a function seems to fail, and there is no way to test whether a property has been declared or not (I get a run time error in JavaScript if I compare an undeclared variable to the ‘undefined’ constant - total bummer). I’m sure there is a way to get the JavaScript to more dynamically handle incoming JSON objects with clever metadata, but right now the structures are nearly fully defined in both the client-side and the server-side code. Bad for maintenance, bad for street cred. I’ll let you know when I’ve overcome that one, too.

social bookmark of choice:
  • Digg
  • del.icio.us
  • Ma.gnolia
  • Reddit
  • Slashdot

Tags:

Leave a Reply