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.
- Login to the BIG-IP Administrative GUI.
- Select the Profiles option under Local Traffic and Virtual Servers
- Select the Statistics from the Other menu.
- Click the Create button
- Enter "user_experience" for the Profile name
- Add the following fields: count_20x, count_30x, count_40x, count_50x, num_requests, and total_time
- 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.
- Select Rules from the Local Traffic/Virtual Servers menu.
- Click the Create button.
- Enter "user_experience" for the iRule name and enter the iRule from below into the Definition text box.
- 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:
- Select Virtual Servers from the Local Traffic menu.
- Click on your Virtual Server to enter it's properties
- Make sure the Advanced Configuration option is selected, and scroll down to the Statistics Profile option
- Select the previously created profile user_experience
- Click the Update Button
- Select the Resources Menu
- Click the Manage Rules button
- 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, ...).
- Wes_98712NimbostratusJust furthers my belief that F5 is way ahead of everyone.
- Leslie_South_55Nimbostratuscan you provide some help on this error:
- Craig_Jackson_2NimbostratusSeems like Statistics Profiles would be even more useful if they were exposed in the UI.
- hooleylistCirrostratusA few related CR's:
- stein_87754Nimbostratusit breaks on v10
- stein_87754Nimbostratusmy bad, i didnt bother reading it before pasting it :-×
- Chris_MillerAltostratusAs Stein said, this throws errors...line 11 should be changed from:
- Michal_Seckar_3Altostratus
Please how can i call it from api ??? I cannot figure it out... :(
asking like this but it dont work :