Heatmaps Part4

Problem this snippet solves:

The final installment of the HeatMaps tech tip series, here is the completed project. A this stage you can view the entire world map, zoom to different regions, sort by URI, and you even get a readout of the actual numbers that are driving the maps being generated so you can tell exactly how many requests per region you're getting to each URI in question. Full tech tip here

Code :

when RULE_INIT {
##  Configure static portions of the HTML response for the heatmap pages
  set static::resp1 "<HTML><table width='100%' border='0'><tr><td></td><td><center><font size=5>Here is your site's usage:\
</font></td></tr><tr><td align='center' rowspan='5'><b><u>Connections per Region:</u></b>"
  set static::resp2  "</td><td><center><img src='http://chart.apis.google.com/chart?cht=t&chd=&chs=440x220&chtm="
  set static::resp3 "&chco=f5f5f5,edf0d4,6c9642,365e24,13390a' border='0'></center></td></tr><td><center>Zoom to region:\
 <a href='/asia'>Asia</a> | <a href='/africa'>Africa</a> | <a href='/europe'>Europe</a> | <a href='/middle_east'>Middle East</a> | \
<a href='/south_america'>South America</a> | <a href='/usa'>United States</a> | <a href='/heatmap'>World</a></td></tr><tr><td><center>"
  set static::resp4 "<tr><td><center><a href='/resetmap'>Reset All Counters</a></center></td></tr><tr></tr></HTML>"

when HTTP_REQUEST timing on {
  switch -glob [string tolower [HTTP::uri]] {
    "/asia*" -
    "/africa*" -
    "/europe*" -
    "/middle_east*" -
    "/south_america*" -
    "/usa*" -
    "/world*" -
    "/heatmap*" {
      set chld ""
      set chd ""
      set zoom ""
      set zoomURL ""
      set regions ""
      set urlTotal 0
      set regionTotal 0
##  Split apart the zoom region from the filter URL in the request
      set zoom [getfield [string map {"/" "" "heatmap" "world"} [HTTP::uri]] "?" 1]
      set zoomURL [getfield [string map {"/" "" "heatmap" "world"} [HTTP::uri]] "?" 2]
##  Get a list of all states or countries, applying the URL filter where necessary
##  and retrieve the associated count of requests from that area to that URL
  ##  First step through the mytables table, which is a pointer table referencing all subtables with counter values in them
      foreach mysub [table keys -subtable mytables] {
  ##  Next determine whether to search state or country tables
        if {$zoom eq "usa"} {
          if {$mysub starts_with "state:"} {
  ##  For each state sub table step through each key, which will be a URL, and count the request to that URL.
  ##  This is also where URL filtering is applied if applicable
            foreach myurl [table keys -subtable $mysub] {
              if {$zoomURL ne ""} {
                if {$myurl eq $zoomURL} {
                  append chld "[getfield $mysub ":" 2]"
                  append chd "[table lookup -subtable $mysub $myurl],"
                  set urlTotal [table lookup -subtable $mysub $myurl]
              } else {
                append chld "[getfield $mysub ":" 2]"
                append chd "[table lookup -subtable $mysub $myurl],"
                set urlTotal [table lookup -subtable $mysub $myurl]
              set regionTotal [expr $regionTotal + $urlTotal]
              set urlTotal 0
            append regions "[getfield $mysub ":" 2] : $regionTotal"
            set regionTotal 0

##  Send back the pre-formatted response, set in RULE_INIT, combined with the map zoom, list of areas, and requ
est count
      set chd [string trimright $chd ","]
  ##  First loop through the trackingurls class to get a list of all URLs to be tracked and format HTML around
them for links
      set filters ""
      foreach mytrackingurl [class names trackingurls] {
        append filters "<a href='${zoom}?${mytrackingurl}'>${mytrackingurl}</a> | "
      set filters [string trimright $filters " | "]

  ##  Combine the above generated HTML with the static HTML in RULE INIT and respond to the client
     HTTP::respond 200 content "${static::resp1}${regions}${static::resp2}${zoom}&chd=t:${chd}&chld=${chld}${st
atic::resp3} \
     Filter by URL: <a href='/$zoom'>All URLs</a> | $filters\

    "/resetmap" {
      foreach pointertable [table keys -subtable mytables] {
        foreach entry [table keys -subtable $pointertable] {
          table delete -subtable $pointertable $entry
      foreach pointerentry [table keys -subtable mytables] {
        table delete -subtable mytables $pointerentry
      HTTP::respond 200 Content "<HTML><center>Table Cleared. <a href='/hea
tmap'>Return to Map</a></HTML>"

    default {
##  Look up country & state locations
      set cloc [whereis [IP::client_addr] country]
      set sloc [whereis [IP::client_addr] abbrev]

##  If the IP doesn't resolve to anything, pick a random IP (useful for testing on private networks)
      if {($cloc eq "") and ($sloc eq "")} {
        set ip [expr { int(rand()*255) }].[expr { int(rand()*255) }].[expr { int(rand()*255) }].[expr { int(ran
d()*255) }]
        set cloc [whereis $ip country]
        set sloc [whereis $ip abbrev]
        if {($cloc eq "") or ($sloc eq "")} {
            set cloc "US"
          set sloc "WA"

##  Strip slashes from URI to allow easy queries
      set friendlyURL [string map {/ ""} [HTTP::uri]]
##  Create a new table named country:location or state:location
      if {[table incr -subtable country:$cloc -mustexist $friendlyURL] eq ""} {
        table set -subtable country:$cloc $friendlyURL 1 indefinite indefinite
##  Update the mytables pointer table with the new country or state table name
      if {[table incr -subtable mytables -mustexist country:$cloc] eq ""} {
        table set -subtable mytables country:$cloc 1 indefinite indefinite
##  Same as above for states, not countries.
      if {$cloc eq "US"} {
        if {[table incr -subtable state:$sloc -mustexist $friendlyURL] eq ""} {
            table set -subtable state:$sloc $friendlyURL 1 indefinite indefinite
        if {[table incr -subtable mytables -mustexist state:$sloc] eq ""} {
            table set -subtable mytables state:$sloc 1 indefinite indefinite
      HTTP::respond 200 Content "Added - Country: $cloc State: $sloc"
Updated Nov 15, 2022
Version 2.0

Was this article helpful?

1 Comment

  • Micha's avatar
    Icon for Nimbostratus rankNimbostratus

    Hi Colin, i have created an irule with tables and that is working fine on VE. but i installed this irule on an viprion and when i ask the information of the table with an other irule, this irule persent the information in an website, i don't see the table information. do you have any idea?