In my previous two posts, I showed how I added live CPU usage and Memory usage to my blog layout to let people see how my Raspberry Pi is holding up hosting a CFML site.  There's one more stat I wanted to add and that is a hit counter so you know how many requests have been served in the last hour.  Since there's no web server logs to parse, I added a simple counter in CFML.  

Getting The Data

This little snippet got added to my Application.cfc's onRequestStart().  It  should really probably go in a preProcess() interceptor inside a module, but I'm feeling rather quick and dirty today.

param name="application.hitLog" default="#[]#";

application.hitLog.append( getTickCount() );

lock name="application.hitLog" type="exclusive" timeout=20 {
	var oneHourAgo = getTickCount() - ( 60 * 60 * 1000 );
	for( var i=1; i<=application.hitLog.len(); i++ ) {
		var entry = application.hitLog[ i ];
		if( entry < oneHourAgo ) {
			application.hitLog.deleteAt( 1 );
			i--;
		} else {
			break;
		}
	} // End loop
} // End lock

That code simply keeps an array of tick count values that correspond with each CFML request to the application.  Each request, loops through and weeds out any requests which are older than 60 minutes.  It's crude, but effective and I don't expect any large amount of load so the array shouldn't ever get too big.  Even if there IS more traffic, the reaping mechanism short circuits as soon as it finds fresh data so the loop shouldn't ever have to process many indexes either way.

Displaying The Data

Once again, I turned to ContentBox widgets because they're so dang useful and easy to write.  This one simply looks like so:

any function renderIt(){
	var hitCount = numberFormat( application.hitLog.len(), ',' );
	return '
		Requests Processed
		<br>
		<h1>#hitCount#</h1>
	';
}

As part of my cache-busting work, I actually moved the calls to the widgets out of my Layouts's .cfm files and into a pieces of content called "stats".  I used a page because, unlike content store items, pages have a URL route assigned to them automatically.  This is all the header of my layouts has in it:

<div style="float:right;border:1px solid white;" id="stat_container">
   Loading...
</div>

And this is what the status page looks like.  Notice the sweet CKEditor integrations where the widgets are inserted all via the nice buttons on the interface.

When this page is rendered, all three widgets are executed, and their returned HTML gets output.  This replaces what I was doing earlier with the #cb.widget( "widgetName" )# code.  

Bust That Cache

ContentBox CMS has a lot of sweet features that come naturally given the fact that it's built on the ColdBox MVC Platform which is just chock full of useful things.  ContentBox leverages CacheBox for quick and easy caching of all your rendered content, including the layouts at the flip of a setting.  This can really make your site blazing fast and even means you can offload all the cache to an external store like Couchbase.  

The problem with caching is that it caches the entire page which means visitors would get stale stats.  One solution for this is to stop outputting the dynamic data directly into the layout and Ajax in the details on page load.  This is why I moved the stats into their own ContentBox page. I set the "Stats" page to not show in the menu, so it's active but only visible if you link straight to it.  Then this snippet of JavaScript was added to my layout.

<script language='javascript'>

        function loadStats() {
                $.ajax({
                        url: "/stats",
                }).done(function( res  ) {
                        $( '#stat_container' ).html( res );
                });
        }

        $( document ).ready(function() {
                loadStats();
                setInterval(function(){ loadStats(); }, 60000);
        });
</script>

This grabs the HTML for the stats and sticks them in the page on document ready.  It also starts an interval to reload the status every 60 seconds, which is how often CPU and memory get updated.  I had one small issue, and that is I didn't want the stats page to get wrapped in a layout, or any of the standard "page" boilerplate.  For this, I created a "blank" layout in ContentBox that simply has the following code and selected it as the layout for the Stats page.

<cfoutput>
        #prc.page.rendercontent()#
</cfoutput>

And the final, important bit-- content caching is enabled for all content by default, so I override caching to be off for THIS CONTENT ITEM.  ContentBox really has thought of everything!

The Finished Product

The end result is a nice little "Loading..." box at the top of each page that loads in after a second and refreshes for as long as the window is open.  

The memory is usually pretty boring with only the saw-tooth pattern of the used heap, but it does look cool when I reboot the Pi and it all starts from the bottom again.  I've also never seen the CPU graph go above 40% and that was after I mashed down the F5 key for a while to test the hit counter.  Go easy on your refresh button, please.  I haven't even put the heat sinks on my Pi's chip :)