Forum Discussion

GavinW_29074's avatar
GavinW_29074
Icon for Nimbostratus rankNimbostratus
May 21, 2012

Enable iRule debugging for connection...

Hi there,

I hit a scenario internally whereby it was deemed very helpful if you could enable iRule debugging on a per connection basis. This meant that for a production system, you could enable debugging for one specific connection without having to slow the entire system down by enabling global debugging... I also wanted this to persist for the entire connection, so that you could run around the application as if you would normally.

So I had a quick look around Devcentral, and couldn't find anything that ticked the required boxes. However I did find https://devcentral.f5.com/wiki/iRules.Select_pool_member_based_on_HTTP_query_string_parameter.ashx, which did some of what I was looking to do.

So I came up with the following.

The iRule allows you to pass in a HTTP Query string as follows:

?f5_debug=[y,Y,n,N]

The iRule parses the incoming request looking for the defined query param, or a corresponding request cookie, and then set's/unset's a variable called f5_connection_debug. It's then possible to use this variable throughout the rest of your iRules to enable/disable local logging...

The iRule also set's/unset's a cookie as appropriate, to allow the connection debugging to be tracked throughout...

The only issue I've got at the moment is the iRule fails to insert the Cookie in the response if the Application returns a 301/302...

 when RULE_INIT  {
     Debug variable. 
    set static::DebugHandlerDebug 1
     F5 Query param name
    set static::f5_debug_param "f5_debug"
}
when HTTP_REQUEST priority 2 {
    
    if {$static::DebugHandlerDebug} { log local0.info "Processing HTTP_REQUEST at Priority 2." }
    
     Check if from authorized IP address. 
    if { [class match [IP::client_addr] equals Authorized_IPs] } {
        
         Check HTTP Query & Cookie for f5_debug param/value.
        if { [HTTP::query] contains $static::f5_param or [HTTP::cookie $static::f5_param] ne ""} {
            
             Param is present in query string
            if {$static::DebugHandlerDebug} { log local0. "HTTP::query ([HTTP::query]) and/or HTTP::cookie ([HTTP::cookie $static::f5_param]) contains $static::f5_debug_param" }
            
             Assign the value from cookie first, with Query string taking precedence. 
            set f5_debug_value [HTTP::cookie $static::f5_param]
            
             Log out cookie value if required
            if {$static::DebugHandlerDebug} { log local0. "Cookie value of $static::f5_debug_param is $f5_debug_value." }
            
             Get the query param value, in lower case
            set f5_debug_query_value [string tolower [URI::query "?[HTTP::query]" "$static::f5_debug_param"]]
            
             Log out param value if required
            if {$static::DebugHandlerDebug} { log local0. "Param value of $static::f5_debug_param is $f5_debug_query_value." }
            
             Check if need to update cookie sourced value with query sourced value
            if { $f5_debug_query_value ne "" } {
                if { $f5_debug_query_value ne $f5_debug_value } {
                     Query param value is not null and doesnt match cookie value, therefore update $f5_debug_value.
                    if {$static::DebugHandlerDebug} { log local0. "Cookie value ($f5_debug_value) doesn't match HTTP::query value ($f5_debug_query_value). Updating \$f5_debug_value from query param value." }
                    
                     Save the cookie value for reference later. 
                    set f5_debug_cookie_value $f5_debug_value
                    
                     Update the value
                    set f5_debug_value $f5_debug_query_value
                    
                } else {
                     Query param value matches cookie value, therefore don't bother updating $f5_debug_value.
                    if {$static::DebugHandlerDebug} { log local0. "Cookie value ($f5_debug_value) matches HTTP::query value ($f5_debug_query_value). Not updating \$f5_debug_value." }
                    
                     Save the cookie value for reference later. 
                    set f5_debug_cookie_value $f5_debug_value
                }
            } else {
                 Query param value is null, therefore don't bother updating $f5_debug_value.
                if {$static::DebugHandlerDebug} { log local0. "\$f5_debug_query_value value is null. Not updating \$f5_debug_value." }
                
                 Save the cookie value for reference later. 
                set f5_debug_cookie_value $f5_debug_value
            }
            
             Final log of $f5_debug_value.
            if {$static::DebugHandlerDebug} { log local0. "Final \$f5_debug_value is $f5_debug_value." }
            
             Check for null values
            if {$f5_debug_value ne ""}{
                
                 Enable or disable debugging?
                switch -glob $f5_debug_value {
                    "y" {
                         Enabling debugging.
                        if {$static::DebugHandlerDebug} { log local0. "Enabling debugging." }
                        
                         Set the Connection Debug value. 
                        set f5_connection_debug 1
                        
                        return
                    }
                    "n" {
                         Disabling debugging.
                        if {$static::DebugHandlerDebug} { log local0. "Disabling debugging." }
                        
                         Un-set the Connection Debug value. 
                        set f5_connection_debug 0
                        
                        return
                    }
                }
                
            }
            
        } else {
            if {$static::DebugHandlerDebug} { log local0. "HTTP::query ([HTTP::query]) or HTTP::cookie ([HTTP::cookie $static::f5_param]) doesn't contains $static::f5_param" }
             Assign default values. 
            set f5_debug_value "n"
            set f5_debug_cookie_value "n"
            
        }
        
    }
}
when HTTP_RESPONSE priority 10 {
    if {$static::DebugHandlerDebug} { log local0.info "Processing HTTP_RESPONSE at Priority 10." }
     Check if $f5_debug_value is set and has a value.
    if {[info exists f5_debug_value] and $f5_debug_value ne ""}{
    
        if {$static::DebugHandlerDebug} { log local0.info "\$f5_debug_value = $f5_debug_value, \$f5_debug_cookie_value = $f5_debug_cookie_value" }
    
         Look for a difference between the debug value and cookie value. Only then do need to change cookies. 
        if { $f5_debug_value ne $f5_debug_cookie_value } {
    
        if {$static::DebugHandlerDebug} { log local0.info "\$f5_debug_value doesn't match \$f5_debug_cookie_value. Handling cookie creation/expiration as appropriate." }
        
             Create or expire cookie? 
            switch -glob $f5_debug_value {
                "y" {
                     Enabling debugging.
                    if {$static::DebugHandlerDebug} { log local0. "Creating cookie..." }
                    
                     Insert cookie in response. 
                    HTTP::cookie insert name $static::f5_debug_param value $f5_debug_value path "/"
                    
                    return
                }
                "n" {
                     Disabling debugging.
                    if {$static::DebugHandlerDebug} { log local0. "Expiring cookie..." }
                    
                     Insert cookie in response & expire it. 
                    HTTP::cookie insert name $static::f5_debug_param value $f5_debug_value path "/"
                    HTTP::cookie expires $static::f5_debug_param 0 absolute
                    
                    return
                }
            }
        } else {
             $f5_debug_value matches $f5_debug_cookie_value. 
            if {$static::DebugHandlerDebug} { log local0.info "\$f5_debug_value matches \$f5_debug_cookie_value. No further processing required." }
            return
        }
    }
    
} 

As always, comments and/or improvements are more than welcome.

Regards

Gavin