tt_linktracking-2-1A common request from application developers is the ability to track the popularity of different areas of their applications.  This could be which app is most popular or which image is linked to most often.  Analytics packages such as Google Analytics do a great job with this but they require injection of client side JavaScript to tell the analytics products about the page views.

In my previous article titled “Link Tracking With iRules - Part 1”, I showed how to implement a simple link tracker application without any modifications to the application or It’s page content.  One, of the several, limitations that this example had was the fact that it tracked all URI’s coming in through the LTM.  In a relatively short amount of time, this list can grow unmanageable.  I’m going to use this article to show how we can add filtering to the resulting data so that you can build a searchable result of your tracking data.

In the previous article, I talked about the basics of how the iRule worked with storing and retrieving the data.  I’m not going to repeat that here so If you missed reading it, you might want to take a minute and read it now.

Ok, now that you’ve read the basics, here’s the extensions I’ve added to allow filtering of the results.

The Filter UI Elements

The result data consists of a URI and it’s reference count.  So, in the HTML page content result form, I inserted two text input boxes.  One with an id of “data_filter” and the other with “count_filter” and placed them at the top of their respective columns in the administration page.  I added custom JavaScript “onKeyDown” handlers to override the default form submission behavior of those elements.  In those functions, I extracted the filter from the associated input box and refreshed the page with the new command argument formats

  • /linkadmin/f(data_filter)
  • /linkadmin/c(count_filter)

where data_filter and count_filter are the values the user supplied in the text boxes.

   1: append content {<tr><td align='left'>Filter&nbsp;Results&nbsp;}
   2: append content "<input type='text' id='data_filter' size='50' value='$data_filter'" 
   3: append content { onkeydown="if (event.keyCode == 13) { 
   4:   window.location.assign('/linkadmin/f(' + encodeURI(getElementById('data_filter').value) + ')') }"/>
   5:   [<a href='/linkadmin'>x</a>]
   6:   </td>}
   7: append content "<td nowrap='nowrap'><input type='text' id='count_filter' size='3' value='$count_filter'" 
   8: append content { onkeydown="if (event.keyCode == 13) { 
   9:   window.location.assign('/linkadmin/c(' + encodeURI(getElementById('count_filter').value) + ')') }"/> 
  10:   [<a href='/linkadmin'>x</a>]
  11:   </td></tr>};

Processing the Filters

If the user types something in the input field and they then press the enter key (keyCode = 13), The page is then refreshed with these parameters being sent to the iRule.  If the argument starts with “f(" and ends with “)”, then I extract the value with the string range command and use that as a filter.  Else if the message starts with “c(“ and ends with “)”, I’ll pull the value out and use that as the count filter.  These values are used in the next section when processing the report table.

   1: set msg [URI::decode [getfield [HTTP::uri] "/" 3]]
   2: if { ($msg starts_with "f(") && ($msg ends_with ")") } {
   3:   set count_filter "";
   4:   set data_filter [string range $msg 2 end-1];
   5:   set msg "";
   6: } elseif { ($msg starts_with "c(") && ($msg ends_with ")") } {
   7:   set count_filter [string range $msg 2 end-1];
   8:   set data_filter "";
   9:   set msg "";
  10: }

Filtering the Results

In the previous article, all the keys in the subtable were iterated upon and added to the result table.  In this example, I’ve added a few conditionals in there to test to see if the “data_filter” or “count_filters” were present in the request.

tt_linktracking-2-3tt_linktracking-2-2If a “data_filter” was present, I still iterate through all the keys but then use the “string match” command to do a wildcard based match on the key.  If a match was made, then the reference count is extracted with the “table lookup” command and presented to the user.

Else if a “count_filter” was present, the reference count is retrieved with the “table lookup” command and then a test is made to see if the reference count is greater than or equal to the value of the filter.  If so, it’s result is presented in the report.

   1: foreach key [table keys -subtable $TABLE_LINK] {
   2:   if { "" != $data_filter } {
   3:     if { [string match $data_filter $key] } {
   4:       set v [table lookup -subtable $TABLE_LINK $key];
   5:       append content "<tr><td>\[<a href='/linkremovedata/$key'>x</a>\] $key</td><td>$v</td></tr>";
   6:     }
   7:   } elseif { "" != $count_filter } {
   8:       set v [table lookup -subtable $TABLE_LINK $key];
   9:       if { $v >= $count_filter } {
  10:         append content "<tr><td>\[<a href='/linkremovedata/$key'>x</a>\] $key</td><td>$v</td></tr>";
  11:       }
  12:   } else {
  13:     set v [table lookup -subtable $TABLE_LINK $key];
  14:     append content "<tr><td>\[<a href='/linkremovedata/$key'>x</a>\] $key</td><td>$v</td></tr>";
  15:   }
  16: }

Still More To Come!

In the next addition to this iRule, I will add the ability to create pre-filters to only track URIs that match specified search patterns.

Get The Source

The source code for this application can be downloaded the LinkTracking2 topic in the iRules CodeShare.

Related Articles on DevCentral

Technorati Tags: iRules, Link, Tracking, table, reporting