Custom Reporting with iRules

In BIG-IP version 9.2, a new profile type was added that is very powerful but isn't well understood. The Statisitcs Profile enables the creation of custom statistics. What makes it interesting is that it's accessible from within iRules. What does this mean to you? Well, for starters, you can extract information from within a connection and store that data for later retrieval.

The Scenario:

Here's a typical situation: You want your web application to provide the best user experience possible. How do you measure that? We'll there are complex monitoring systems to simulate user actions, the time it takes for pages to refresh, the number of HTTP errors returned, etc. But let's say your needs aren't that great. You just want to know what the error rate is and how fast pages are getting served to the client. And to top that off, you'll want a way to control and view those statistics. Enter iRules and the Statistics Profile...

The setup:

This is assuming you already have a virtual server fronting your application and that you are running BIG-IP v9.2 or greater.

Create the Statistics Profile

The heart of this solution is the statistics profile. A statistics profile is a set of name=value pairs where the names are strings and the values are numbers.

  1. Login to the BIG-IP Administrative GUI.
  2. Select the Profiles option under Local Traffic and Virtual Servers
  3. Select the Statistics from the Other menu.
  4. Click the Create button
  5. Enter "user_experience" for the Profile name
  6. Add the following fields: count_20x, count_30x, count_40x, count_50x, num_requests, and total_time
  7. Click Update to create the profile

Create the iRule

Now that the virtual server is setup with the statistics profile, you'll need to create an iRule to update the profile with the statistics.

  1. Select Rules from the Local Traffic/Virtual Servers menu.
  2. Click the Create button.
  3. Enter "user_experience" for the iRule name and enter the iRule from below into the Definition text box.
  4. Click Finished to save the iRule

Apply the statistics profile to your virtual server

The statistics profile doesn't do much until you apply it to a virtual servers properties. Here's how:

  1. Select Virtual Servers from the Local Traffic menu.
  2. Click on your Virtual Server to enter it's properties
  3. Make sure the Advanced Configuration option is selected, and scroll down to the Statistics Profile option
  4. Select the previously created profile user_experience
  5. Click the Update Button
  6. Select the Resources Menu
  7. Click the Manage Rules button
  8. Make sure the user_experience iRule is in the Enabled list box and click the Finished button.

The Fun

So now that the grunt work is done, here's the fun stuff - the iRule.

when RULE_INIT {
  # store the profile name in a variable for easy modification later.
  set ::PROFILE_NAME "user_experience"
}

when HTTP_REQUEST {
  # store the number of milliseconds since the epoch (you'll find out why later)
  set t0 [clock clicks -milliseconds]

  # add some secret control functions to manipulate the statistics
  switch [string tolower [HTTP::uri]] {

    "/getuserstats" {
      # Avoid divide by zero errors
      set time_per_req 0
      set total_time [STATS::get $::PROFILE_NAME total_time]
      set num_requests [STATS::get $::PROFILE_NAME num_requests]
      if { $num_requests > 0 } {
        set time_per_req [expr $total_time / $num_requests]
      }

      # Hand roll a HTTP response to serve up the statistics report
      HTTP::respond 200 content "<html>
        <head><center><title>HTTP Status Code Report</title>
        <style>body {font-family: Tahoma}
        td {text-align: center}
        </style>
        </head><body>
        <table border='1' cellpadding='5' cellspacing='0'>
        <tr><th>HTTP<br/>Status Code</th><th>Response<br/>Count</th></tr>
        <tr><td>20x</td><td>[STATS::get $::PROFILE_NAME count_20x]</td></tr>
        <tr><td>30x</td><td>[STATS::get $::PROFILE_NAME count_30x]</td></tr>
        <tr><td>40x</td><td>[STATS::get $::PROFILE_NAME count_40x]</td></tr>
        <tr><td>50x</td><td>[STATS::get $::PROFILE_NAME count_50x]</td></tr>
        <tr><td>Num Requests</td><td>[STATS::get $::PROFILE_NAME num_requests]</td></tr>
        <tr><td>Total Time</td><td>[STATS::get $::PROFILE_NAME total_time] ms.</td></tr>
        <tr><td>Avg Time/Req</td><td>$time_per_req ms.</td></tr>
        </table></center></body></html>"
    }

    "/resetuserstats" {
      # Reset all the statistics values to zero
      STATS::set $::PROFILE_NAME "count_20x" 0
      STATS::set $::PROFILE_NAME "count_30x" 0
      STATS::set $::PROFILE_NAME "count_40x" 0
      STATS::set $::PROFILE_NAME "count_50x" 0
      STATS::set $::PROFILE_NAME "num_requests" 0
      STATS::set $::PROFILE_NAME "total_time" 0

      # Hand roll a HTTP response indicating reset status
      HTTP::respond 200 content "<html>
        <head><center><title>HTTP Status Code Control</title>
        <body><h1>Statistics Successfully reset</h1>
        </body></html>"
    }
  }
}

when HTTP_RESPONSE {

  # use the clock command to get the delta in milliseconds between
  # the request and the response.  This doesn't give the true
  # time the client waits, but it is pretty close to the server
  # processing time.
  set t1 [clock clicks -milliseconds]
  set total_time [expr $t1 - $t0]

  # Increment the statistics profile values
  switch -glob [HTTP::status] {
    "20*" {
      STATS::incr $::PROFILE_NAME "count_20x" 1
    }
    "30*" {
      STATS::incr $::PROFILE_NAME "count_30x" 1
    }
    "40*" {
      STATS::incr $::PROFILE_NAME "count_40x" 1
    }
    "50*" {
      STATS::incr $::PROFILE_NAME "count_50x" 1
    }
  }
  STATS::incr $::PROFILE_NAME "num_requests" 1
  STATS::incr $::PROFILE_NAME "total_time" $total_time
}

Conclusion

In this example we store the high level HTTP::status categories as well as response time. By adding additional fields the the statistics profile, you can easily extend the functionality of this example.

Oh, and if browsers aren't your preferred method for pulling the stats, know that they are all available via iControl as well so you can pull them down with your own preferred environment (perl, PowerShell, .Net, Java, ...).

Published Mar 07, 2007
Version 1.0

Was this article helpful?

8 Comments

  • can you provide some help on this error:

     

     

    Oct 24 16:10:56 tmm tmm[17883]: 01220001:3: TCL error: Rule user_experiance - Error: user_experience/count_20x: ba"

     

     

  • Seems like Statistics Profiles would be even more useful if they were exposed in the UI.

     

     

    As it is now, it appears that they're very similar to iRule global variables, except that apparently they are exposed in iControl and SNMP.
  • A few related CR's:

     

    ---------------------------------------------------

     

    CR90027 - The stats profile field names must start with a letter and only contain letters, numbers, hyphens and underscores

     

    ---------------------------------------------------

     

    CR117258 - Stats profile field values cannot be retrieved via SNMP!

     

     

    SNMP userStatProfileStat table is broken

     

    "userStatProfileStat table is returning incorrect stats counts. To repro, create a simple profile with a couple keys, then do something

     

    to increment one of the keys. In this case (see below), instead of returning 1, it is returning the decimal equivalent of 0xffffffff. This

     

    is repeatable and used to work on earlier releases. iControl queries return the correct value."

     

     

    - Aaron
  • it breaks on v10

     

     

    01070151:3: Rule [user_experience] error: line 6: [wrong args] [string tolower ] line 14: [use curly braces to avoid double substitution] [$total_time] line 61: [use curly braces to avoid double substitution] [$t1]
  • As Stein said, this throws errors...line 11 should be changed from:

     

     

    switch [string tolower ]HTTP::uri[] {

     

     

    to:

     

     

    switch [string tolower [HTTP::uri]] {

     

     

    Unless of course I'm missing something. I don't do iRules, just what I did to make it work.
  • Please how can i call it from api ??? I cannot figure it out... :(

     

    asking like this but it dont work :