Welcome!

Java IoT Authors: Yeshim Deniz, Pat Romanski, Liz McMillan, Zakia Bouachraoui, Carmen Gonzalez

Blog Feed Post

Monitor Your iRule Performance with iControl and Google-O-Meter Charts

iRule performance has long been a question our users have asked about.  We get questions all the time about how to determine what impact a specific iRule has on the normal operation of the BIG-IP’s they are running on.  The question is a hard one to answer as we rarely see two iRules that are the same and the mere fact that you can code your iRule however you want, makes it very hard to provide info on the impact they would have in a generic manner.

A while back we wrote a tech tip on optimizing iRules titled “Evaluating iRule Performance” in which we illustrate how to enable timing metrics on an iRule to help report the number of CPU cycles the iRule is using up during it’s processing.  We make these metrics available in the BIG-IP CLI and GUI as well as from the iControl API.  This makes it easy to integrate them into external applications such as the iRule Editor.

I’m always thinking of ways to visualize the metrics we can get from iControl and I got to thinking about the article I wrote a while back on Building an iControl PowerShell Monitoring Dashboard with Google Charts and looked again at the Google Charts API to see if anything new had cropped up recently.

For those that don’t know about Google Charts, Google has made available an awesome, in my opinion, API to enable the dynamic creation of charts to include with your own web applications.  At the time of this article, they offer Bar charts, Box charts, Candlestick charts, Compound charts, Dynamic icons, Formulas, GraphViz charts, Line charts, Map charts, Pie charts, QR codes, Radar charts, Scatter charts, Venn charts, and, the one I decided to use in this article, Google-O-Meter charts.

iRule Metrics

By using the “timing on” command within an iRule, several metrics can be retrieved from the LocalLB.Rule.get_statistics() method.  These values are:

  • STATISTIC_RULE_MINIMUM_CYCLES - The minimum number of clock cycles spent during an execution of the rule event.
  • STATISTIC_RULE_AVERAGE_CYCLES - The average number of clock cycles spent during an execution of the rule event.
  • STATISTIC_RULE_MAXIMUM_CYCLES - The maximum number of clock cycles spent during an execution of the rule event.
  • STATISTIC_RULE_ABORTS - The number of aborts due to TCL errors.
  • STATISTIC_RULE_FAILURES - The number of times the iRule has failed for any reason.
  • STATISTIC_RULE_TOTAL_EXECUTIONS - The number of times the iRule event has been executed.

These metrics are on an event by event basis so that means we can get detailed results for each of the events (HTTP_REQUEST, STREAM_MATCHED, etc) used within a given iRule.  From these metrics, along with the speed of the CPU on the target platform, one can calculate metrics such as

  • CPU Cycles/Request
  • Runtime (ms)/Request
  • Percent CPU Usage/Request

Google-O-Meter charts

Google-O-Meter charts are in the form of a gauge and a simple one looks like the image on the right.  It provides a minimum and maximum for the gauge along with a value for the “arms”.  You have full control over the colors and labels so I figured this would be a great way to represent the various metrics we can retrieve from iRules.

With the metrics returned from the iControl API, we could build a dashboard with these charts that illustrated in real-time how the iRule was performing.

The Code

I will follow the model in my previous dashboard example by building an engine in PowerShell that does the data collection and processing.  It will then use the automation features in Internet Explorer to dynamically create a browser instance and feed it with the output from the engine.  The engine will continue processing in a loop and feed the updated statistics to the browser allowing for a dynamically refreshing dashboard.

The script will take the following parameters

  • BIGIP – The address of your BIGIP. 
  • User – The admin user for your BIGIP.
  • Pass – The admin password for your BIGIP.
  • VirtualServer – An optional virtual server name to filter the results on.
  • iRule – An optional iRule name to filter the results on.
  • Metric – The metric you would like reported (“CYCLES”, “RUNTIME”, “CPUUSAGE”, “ALL”)
  • Debug – If set to $true, debug information is displayed to the console during the script operation.
  • Interval – The frequency in seconds between polls.  The default value is 10 (seconds)

The main logic for the engine is a while loop in which data is collected with the Get-Data function and pumped to the instance of Internet Explorer with the Refresh-Browser function.  The script then sleeps during the specified sleep interval and then repeats the procedure.

   1: function Run-Dashboard()
   2: {
   3:   while($true)
   4:   {
   5:     Write-Host "Requesting data..."
   6:     $file_data = Get-Data;
   7:     
   8:     Refresh-Browser $file_data;
   9:     Start-Sleep $script:INTERVAL;
  10:   }
  11: }

Retrieving Data

The Get-Data function is really the heart of this application.  This function requests the list of iRules assigned as resources to the specified Virtual Server(s) as well as the metrics for all the iRules on the system.  I chose to make a single call here to reduce the processing speed of the function.  I could have filtered the results and only queried the metrics or the iRules associated with Virtuals but took the easy road with the get_all_statistics() method.  I’ll leave it an exercise for the reader to make this change.

The script then loops through the virtual servers and builds a table report for each one.  The format of the table each row being an iRule and each column representing the events that are used within that iRule.  I wrote some code to calculate all of the types of events in all iRules for the given virtual server so that we could have a nice layout.

The presentation (HTML) for the dashboard is stored in the $page_data variable and returned to the calling code.

   1: function Get-Data()
   2: {
   3:   $now = [DateTime]::Now;
   4:  
   5:   $page_data = "<html><head><title>$($script:TITLE)</title>
   6:   <style type='text/css'>
   7:     body,td,th { font-family: Tahoma; font-size: 10pt; }
   8:     .datatable { background-color: #C0C0C0; }
   9:     .colheader { background-color: cyan; }
  10:     .rowheader { background-color: yellow; }
  11:   </style>
  12:   </head>
  13:   <center><h1>iRule Monitor</h1><br/><h2>$now</h2>";
  14:  
  15:   $vslist = [string[]]$(Get-VirtualServerList);
  16:   
  17:   $VirtualServerRuleAofA = (Get-F5.iControl).LocalLBVirtualServer.get_rule( $vslist );
  18:   $RuleStatistics = (Get-F5.iControl).LocalLBRule.get_all_statistics();
  19:   
  20:   # loop through all the virtual servers
  21:   for($i=0; $i -lt $VirtualServerRuleAofA.Length; $i++)
  22:   {
  23:     $vs = $vslist[$i];
  24:     
  25:     # rules for current vs
  26:     $VirtualServerRuleA = $VirtualServerRuleAofA[$i];
  27:     
  28:     # rule stats for current vs
  29:     $RuleStatisticEntryA = Filter-RuleStatistics $VirtualServerRuleA $RuleStatistics;
  30:     if ( $RuleStatisticEntryA -ne $null )
  31:     {
  32:       # Build out a column list...
  33:       $columns = @{};
  34:       foreach($RuleStatisticEntry in $RuleStatisticEntryA)
  35:       {
  36:         if ( ($columns.count -eq 0) -or ($null -eq $columns[$RuleStatisticEntry.event_name]) )
  37:         {
  38:           $columns.Add($RuleStatisticEntry.event_name, 0);
  39:         }
  40:       }
  41:       $scolumns = $columns.GetEnumerator() | Sort-Object Name;
  42:       
  43:       # Build out result graphs
  44:       
  45:       Write-DebugMessage "VIRTUAL SERVER $vs";
  46:       
  47:       $page_data += "<table border='1' class='datatable'>"
  48:       $page_data += "<tr><th colspan='$($columns.Count + 1)'>Virtual Server '$vs'</th></tr>";
  49:       
  50:       $page_data += "<tr><th>iRule</th>"
  51:       foreach($key in $scolumns)
  52:       {
  53:         $page_data += "<th class='colheader'>$($key.Name)</th>";
  54:       }
  55:       $page_data += "</tr>";
  56:  
  57:       # loop through all rules for current  virtual server
  58:       foreach($VirtualServerRule in $VirtualServerRuleA)
  59:       {
  60:         if ( ($null -eq $script:IRULE) -or ($VirtualServerRule.rule_name -eq $script:IRULE) )
  61:         {
  62:           $page_data += "<tr>";
  63:           $page_data += "<td class='rowheader'>$($VirtualServerRule.rule_name)</td>";
  64:           
  65:           foreach($key in $scolumns)
  66:           {
  67:             $aborts = $null;
  68:             $avg_cycles = $null;
  69:             $failures = $null;
  70:             $max_cycles = $null;
  71:             $min_cycles = $null;
  72:             $total_executions = $null;
  73:             
  74:             foreach($RuleStatisticEntry in $RuleStatisticEntryA)
  75:             {
  76:               if ( ($RuleStatisticEntry.rule_name -eq $VirtualServerRule.rule_name) -and
  77:                    ($RuleStatisticEntry.event_name -eq $key.Name) )
  78:               {
  79:                 Write-DebugMessage "Searching for '$($RuleStatisticEntry.rule_name), $($RuleStatisticEntry.event_name)...";
  80:                 # Found a match for the row and column
  81:                 $min_cycles = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_MINIMUM_CYCLES";
  82:                 $avg_cycles = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_AVERAGE_CYCLES";
  83:                 $max_cycles = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_MAXIMUM_CYCLES";
  84:                 $aborts = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_ABORTS";
  85:                 $failures = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_FAILURES";
  86:                 $total_executions = Extract-Statistic $RuleStatisticEntry.statistics "STATISTIC_RULE_TOTAL_EXECUTIONS";
  87:                 break;
  88:               }
  89:             }
  90:             
  91:             $min = 0;
  92:             $data_value = $null;
  93:             $max = 5000;
  94:             
  95:             $speedMhz = [Convert]::ToDouble($script:CPUSPEED);
  96:             $speed = [Convert]::ToUInt64(1000000 * $speedMhz);
  97:  
  98:             $cycles_min = $min_cycles;
  99:             $cycles_avg = $avg_cycles;
 100:             $cycles_max = $max_cycles;
 101:  
 102:             $runtime_min = [Convert]::ToDouble($min_cycles) * (1000.0/$speed);
 103:             $runtime_avg = [Convert]::ToDouble($avg_cycles) * (1000.0/$speed);
 104:             $runtime_max = [Convert]::ToDouble($max_cycles) * (1000.0/$speed);
 105:  
 106:             $cpu_min = 0;
 107:             #$min = 100.0 * ([Convert]::ToDouble($min_cycles) / [Convert]::ToDouble($speed));
 108:             $cpu_avg = 100.0 * ([Convert]::ToDouble($avg_cycles) / [Convert]::ToDouble($speed));
 109:             #$max = 100.0 * ([Convert]::ToDouble($max_cycles) / [Convert]::ToDouble($speed));
 110:             $cpu_max = 100;
 111:             
 112:             if ( 0 -eq $data_value ) { $data_value = $null; }
 113:             if ( $null -ne $data_value ) { $data_value = $data_value.ToString("0.0000"); }
 114:             
 115:             $cycles_chart = Get-Chart $cycles_min $cycles_avg $cycles_max "CYCLES";
 116:             $runtime_chart = Get-Chart $runtime_min $runtime_avg $runtime_max "RUNTIME" "0.00000";
 117:             $cpu_chart = Get-Chart $cpu_min $cpu_avg $cpu_max "CPUUSAGE" "0.00000";
 118:             $success_chart = Get-Chart 0 ($aborts + $failures) $total_executions "ERRORS";
 119:  
 120:             Write-DebugMessage $charturl;
 121:             
 122:             $page_data += "<td>";
 123:  
 124:             switch($script:METRIC)
 125:             {
 126:               "CYCLES" {
 127:                 $page_data += "$cycles_chart";
 128:                 $page_data += $success_chart;
 129:               }
 130:               "RUNTIME" {
 131:                 $page_data += "$runtime_chart";
 132:                 $page_data += $success_chart;
 133:               }
 134:               "CPUUSAGE" {
 135:                 $page_data += "$cpu_chart";
 136:                 $page_data += $success_chart;
 137:               }
 138:               "ALL" {
 139:                 $page_data += $cycles_chart;
 140:                 $page_data += $runtime_chart;
 141:                 $page_data += $cpu_chart;
 142:                 $page_data += $success_chart;
 143:               }
 144:               default {
 145:                 $page_data += "$cycles_chart";
 146:               }
 147:             }
 148:             $page_data += "</td>";
 149:           }
 150:           $page_data += "</tr>";
 151:         }
 152:       }
 153:       $page_data += "</table><p>"
 154:     }
 155:   }
 156:   
 157:   $page_data += "</center>";
 158:   
 159:   return $page_data;
 160: }

Generating The Chart

I wrote a little helper function to generate the image reference for the Google-O-Meter chart.  It takes as input the min value for the chart, the value for the arrow, the max value for the chart, the type of chart (for the label) as well as an optional data format specifier (for those pesky small double values).

   1: function Get-Chart()
   2: {
   3:   param($min, $val, $max, $type, $fmt);
   4:   
   5:   $chart = "";
   6:   Write-DebugMessage "Querying chart for '$min', '$val', '$max', '$type'...";
   7:   
   8:   if ( ($null -ne $val) -and ($null -ne $fmt) )
   9:   {
  10:     $val = $val.ToString($fmt);
  11:   }
  12:   
  13:   $suffix = "";
  14:   switch($type)
  15:   {
  16:     "CYCLES" { $suffix = ""; }
  17:     "RUNTIME" { $suffix = " ms."; }
  18:     "CPUUSAGE" { $suffix = "%"; }
  19:   }
  20:   
  21:   $prefix = Get-ChartPrefix;
  22:   $charturl = "http://${prefix}chart.apis.google.com/chart?cht=gom";
  23:   
  24:   $charturl += "&chs=$($script:CHARTSIZE)";
  25:   $charturl += "&chco=00FF00,FF0000";
  26:   $charturl += "&chds=$min,$max";
  27:   $charturl += "&chd=t:$val";
  28:   $charturl += "&chxt=x,y";
  29:   $charturl += "&chxl=0:|$val$suffix|1:|0||$max";
  30:   $charturl += "&chf=c,lg,45,FFE7C6,0,76A4FB,0.75";
  31:   
  32:   Write-DebugMessage "returning chart: $charturl...";
  33:  
  34:   $chart += "<img src='$charturl'/>";
  35:   switch($type)
  36:   {
  37:     "CYCLES" {
  38:       $chart += "<br/><center>CPU Cycles/Request</center>";
  39:     }
  40:     "RUNTIME" {
  41:       $chart += "<br/><center>Runtime (ms)/Request</center>";
  42:     }
  43:     "CPUUSAGE" {
  44:       $chart += "<br/><center>Percent CPU Usage/Request</center>";
  45:     }
  46:     "ERRORS" {
  47:       $chart += "<br/><center>Total Errors</center>";
  48:     }
  49:   }
  50:   
  51:   $chart += "<br/>";
  52:     
  53:   return $chart;
  54: }

Feeding Results To The Browser

The Refresh-Browser function will feed the data to the browser.  It first checks to see if a browser instance has been created and, if not, creates it.  It then updates the browsers Document.DocumentElement.lastChild.InnerHTML property to dynamically update the contents of the page.  This causes the page to refresh itself.

   1: function Refresh-Browser()
   2: {
   3:   param($file_data);
   4:   
   5:   if ( $null -eq $script:BROWSER )
   6:   {
   7:     Write-DebugMessage "Creating new Browser"
   8:     $script:BROWSER = New-Object -com InternetExplorer.Application;
   9:     $script:BROWSER.Navigate2("About:blank");
  10:     $script:BROWSER.Visible = $true;
  11:     $script:BROWSER.TheaterMode = $script:THEATER;
  12:   }
  13:   $docBody = $script:BROWSER.Document.DocumentElement.lastChild;
  14:   $docBody.InnerHTML = $file_data;
  15: }

The Results

The following is how the application looks when run with the following parameters.  I’ve specified to monitor the virtual server ‘DC5’ and only the ‘dc.dc5_stream’ iRule.  It will present graphs for all the available metrics.

   1: PS> .\PsiControlDashboard.ps1 -BIGIP bigip -User user -Pass pass -VirtualServer DC5 -iRule "dc.dc5_stream" -Metric "ALL"

 

tt_irulemonitor_3

Get The Code

The full PowerShell script is available in the iControl CodeShare under PsIruleDashboard.

 

Related Articles on DevCentral

Read the original blog entry...

More Stories By Joe Pruitt

Joe Pruitt is a Principal Strategic Architect at F5 Networks working with Network and Software Architects to allow them to build network intelligence into their applications.

IoT & Smart Cities Stories
Dion Hinchcliffe is an internationally recognized digital expert, bestselling book author, frequent keynote speaker, analyst, futurist, and transformation expert based in Washington, DC. He is currently Chief Strategy Officer at the industry-leading digital strategy and online community solutions firm, 7Summits.
Digital Transformation is much more than a buzzword. The radical shift to digital mechanisms for almost every process is evident across all industries and verticals. This is often especially true in financial services, where the legacy environment is many times unable to keep up with the rapidly shifting demands of the consumer. The constant pressure to provide complete, omnichannel delivery of customer-facing solutions to meet both regulatory and customer demands is putting enormous pressure on...
IoT is rapidly becoming mainstream as more and more investments are made into the platforms and technology. As this movement continues to expand and gain momentum it creates a massive wall of noise that can be difficult to sift through. Unfortunately, this inevitably makes IoT less approachable for people to get started with and can hamper efforts to integrate this key technology into your own portfolio. There are so many connected products already in place today with many hundreds more on the h...
The standardization of container runtimes and images has sparked the creation of an almost overwhelming number of new open source projects that build on and otherwise work with these specifications. Of course, there's Kubernetes, which orchestrates and manages collections of containers. It was one of the first and best-known examples of projects that make containers truly useful for production use. However, more recently, the container ecosystem has truly exploded. A service mesh like Istio addr...
Digital Transformation: Preparing Cloud & IoT Security for the Age of Artificial Intelligence. As automation and artificial intelligence (AI) power solution development and delivery, many businesses need to build backend cloud capabilities. Well-poised organizations, marketing smart devices with AI and BlockChain capabilities prepare to refine compliance and regulatory capabilities in 2018. Volumes of health, financial, technical and privacy data, along with tightening compliance requirements by...
Charles Araujo is an industry analyst, internationally recognized authority on the Digital Enterprise and author of The Quantum Age of IT: Why Everything You Know About IT is About to Change. As Principal Analyst with Intellyx, he writes, speaks and advises organizations on how to navigate through this time of disruption. He is also the founder of The Institute for Digital Transformation and a sought after keynote speaker. He has been a regular contributor to both InformationWeek and CIO Insight...
Andrew Keys is Co-Founder of ConsenSys Enterprise. He comes to ConsenSys Enterprise with capital markets, technology and entrepreneurial experience. Previously, he worked for UBS investment bank in equities analysis. Later, he was responsible for the creation and distribution of life settlement products to hedge funds and investment banks. After, he co-founded a revenue cycle management company where he learned about Bitcoin and eventually Ethereal. Andrew's role at ConsenSys Enterprise is a mul...
To Really Work for Enterprises, MultiCloud Adoption Requires Far Better and Inclusive Cloud Monitoring and Cost Management … But How? Overwhelmingly, even as enterprises have adopted cloud computing and are expanding to multi-cloud computing, IT leaders remain concerned about how to monitor, manage and control costs across hybrid and multi-cloud deployments. It’s clear that traditional IT monitoring and management approaches, designed after all for on-premises data centers, are falling short in ...
In his general session at 19th Cloud Expo, Manish Dixit, VP of Product and Engineering at Dice, discussed how Dice leverages data insights and tools to help both tech professionals and recruiters better understand how skills relate to each other and which skills are in high demand using interactive visualizations and salary indicator tools to maximize earning potential. Manish Dixit is VP of Product and Engineering at Dice. As the leader of the Product, Engineering and Data Sciences team at D...
Dynatrace is an application performance management software company with products for the information technology departments and digital business owners of medium and large businesses. Building the Future of Monitoring with Artificial Intelligence. Today we can collect lots and lots of performance data. We build beautiful dashboards and even have fancy query languages to access and transform the data. Still performance data is a secret language only a couple of people understand. The more busine...