Forum Discussion

ahmad_2312's avatar
ahmad_2312
Icon for Nimbostratus rankNimbostratus
Jul 09, 2011

Measuring Response time based on POST and GET Parameters

HI

 

 

I am trying to measure the response time of each transaction in our website, however due to security reasons all URLs are masked and the only way to identify the page is by using a submitted form's parameter called hidActionName, the parameter is submitted in some pages using GET method and in other in POST, i tried my best and came up with this , but it didnt work ... can you help please:

 

 

when HTTP_REQUEST {

 

 

set http_request_time [clock clicks -milliseconds]

 

set theurl [HTTP::uri]

 

set theip [IP::client_addr]

 

set wmethod [HTTP::method]

 

 

Only check POST requests

 

if { [HTTP::method] eq "POST" } {

 

 

Default amount of request payload to collect (in bytes)

 

set collect_length 2048

 

 

Check for a non-existent Content-Length header

 

if {[HTTP::header Content-Length] eq ""}{

 

 

Use default collect length of 2k for POSTs without a Content-Length header

 

set collect_length $collect_length

 

 

} elseif {[HTTP::header Content-Length] == 0}{

 

 

Don't try collect a payload if there isn't one

 

unset collect_length

 

 

} elseif {[HTTP::header Content-Length] > $collect_length}{

 

 

Use default collect length

 

set collect_length $collect_length

 

 

} else {

 

 

Collect the actual payload length

 

set collect_length [HTTP::header Content-Length]

 

 

}

 

 

If the POST Content-Length isn't 0, collect (a portion of) the payload

 

if {[info exists collect_length]}{

 

 

Trigger collection of the request payload

 

HTTP::collect $collect_length

 

}

 

}

 

}

 

 

when HTTP_REQUEST_DATA {

 

set ActionName [URI::decode [URI::query "?[HTTP::payload]" hidActionName]]

 

 

}

 

 

 

when HTTP_RESPONSE {

 

set http_response_time [ clock clicks -milliseconds ]

 

 

 

log 10.0.10.16:514 local0. "CEF:0|XXX|XXXX|10.2|200|Response Time|2|src=$theip request=$theurl cn1=[expr $http_response_time - $http_request_time] cs1=$wmethod cs2=$ActionName"

 

 

}

 

  • using the following code, i was able to get the response time based on POST and GET Parameters, however i am still getting some TCL Error in logs

     

     

    TCL error: Response_Time_2 - Illegal argument (line 9) invoked from within "HTTP::collect [HTTP::header Content-Length]" ("POST" arm line 3) invoked from within "switch [HTTP::method] { "GET"

     

     

    
    when HTTP_REQUEST {
      
    set http_request_time [clock clicks -milliseconds]
    set theurl [HTTP::uri]
    set theip [IP::client_addr]
    set wmethod [HTTP::method]
    set contype [HTTP::header Content-Type]
    set POSTQuery ""
    set GETQuery ""
    
      switch [HTTP::method] {
        "GET" {
           Inspect Query String
         
          set GETQuery [string tolower [URI::query "?&[HTTP::query]" hidActionName]]
        }
        "POST" {
          if { [HTTP::header Content-Type] eq "application/x-www-form-urlencoded" } {
            HTTP::collect [HTTP::header Content-Length]
          }
        }
      }
    }
    
    when HTTP_REQUEST_DATA {
    
    set POSTQuery [string tolower [URI::query "?[HTTP::payload]" hidActionName]]
      }
    
    
    when HTTP_RESPONSE {
    
    set http_response_time [ clock clicks -milliseconds ]
    log 10.0.10.16:514 local0. "CEF:0|XX|XX|10.2|200|Response Time|2|src=$theip request=$theurl cn1=[expr $http_response_time - $http_request_time] cs1=$wmethod cs2=$contype cs4=$POSTQuery cs6=$GETQuery"
    
    }
    
     
  • Hamish's avatar
    Hamish
    Icon for Cirrocumulus rankCirrocumulus
    Is there a content-length header in the post? (Although collect will take 0 or no parameter, I'm not sure off hand what a missing header will return and pass to the collect routine).

     

     

     

    Just a quick note... I'd use HSL myself (In fact I did use HSL myself :), and accumulate the times... And only send every X seconds the results (Using the after XXX -periodoc {} command . Otherwise you'll rapidly discover that the system won't keep up with a reasonably moderate load.

     

     

    Checkout the LDAP_STATS_MEASURING iRule in the codeshare (http://devcentral.f5.com/wiki/default.aspx/iRules/LDAP_Stats_Measuring.html) which you can undoubtedly alter for your requirements.

     

     

     

    H
  • Hamish is right here. HTTP::header $header_name will return a null string if the header doesn't exist. HTTP::collect expects an integer so that's why you're getting the error.

     

     

    Going back to the original scenario, are you trying to do this for troubleshooting purposes or ongoing reporting? Trying to collect every request payload is going to add latency to the requests and require a non-trivial amount of TMM memory. If you want to troubleshoot a specific issue, using tcpdump might be a more effective method. If you want to do this long term, you might consider the new AVR module in v11.0. It provides these types of metrics and more for web app traffic. You could sign up for the beta on beta.f5.com to get a preview of the functionality (though hurry as it ends this week).

     

     

    If you do want to pursue the iRule route, you might try checking [HTTP::payload] in HTTP_REQUEST without collecting the payload to see if the parameters you need have already been seen in the first packet(s) TMM needs to buffer to parse the request HTTP headers.

     

     

    And as Hamish suggested, definitely consider using High Speed Logging for this instead of the log command. The performance (or lack of resource utilization) is incredible.

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/hsl

     

     

    Aaron
  • Hamish's avatar
    Hamish
    Icon for Cirrocumulus rankCirrocumulus

     

    Here's the code I use for grabbing the content of an HTTP request. Apologies for it being a bit messy... It's in a quick & dirty iRule I wrote a long while ago...

     

     

          
     Trigger collection for up to 1MB of data
          
    if {[HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 1048576}{
            
      set fl_content_length [HTTP::header "Content-Length"]
          
    } else {
            
      set fl_content_length 1048576
    
          }
          
     paranoia... Check if $content_length has been set and is not set to 0
          
    if { [info exists fl_content_length] && $fl_content_length > 0} {
      if { $fl_debugFlag  >= 2 } {
              
        HSL::send $hsl "$fl_logprefix collecting $fl_content_length Bytes"  
        
      }  
            
      HTTP::collect $fl_content_length
          
    }
    

     

     

    H