Forum Discussion
Brad_53264
Nimbostratus
Nov 03, 2008Web Analytics iRule Style
I am attempting to implement Joe's Urchin solution described here http://devcentral.f5.com/Default.aspx?tabid=63&articleType=ArticleView&articleId=174
The iRule described on the above link is working on 99% of my application. I have one specific page, which just hangs the browser when this iRule is present. Included below is the exact iRule I am using. My modifications include making the urchin.js be local, and added additional logging for troubleshooting. Also included is the logging output (scrubbed) from the problem page. Notice how the CLIENT_CLOSED is not triggered until the 5 minute timeout kicks in.
Any assistance with troubleshooting this issue is greatly appreciated.
when RULE_INIT {
replace the value of the _uacct variable with your Google Analytics account.
set analytics "
"
set exist_search "urchinTracker()"
}
when HTTP_REQUEST {
Get time for start of HTTP request
set http_request_time [clock clicks -milliseconds]
Log the start of a new HTTP request
set LogString "Client [IP::client_addr]:[TCP::client_port] -> [HTTP::host][HTTP::uri]"
log local0.info "$LogString (request)"
Don't allow data to be chunked
if { [HTTP::version] eq "1.1" } {
log local0.info "HTTP::version = 1.1"
if { [HTTP::header is_keepalive] } {
log local0.info "is_keepalive = true"
HTTP::header replace "Connection" "Keep-Alive"
log local0.info "Connection is now Keep-Alive"
}
HTTP::version "1.0"
log local0.info "HTTP::version is now 1.0"
}
}
when HTTP_RESPONSE {
Received the response headers from the server. Log the pool name, IP and port, status and time delta
log local0.info "$LogString (response) - pool info: [LB::server] - status: [HTTP::status] (request/response delta: [expr [clock clicks -milliseconds] - $http_request_time]ms)"
if { [HTTP::header Content-Type] starts_with "text/html" } {
if { [HTTP::header exists "Content-Length"] } {
log local0.info "content length: [HTTP::header {Content-Length}]"
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 1000000000
}
log local0.info "Collecting $content_length bytes"
if { $content_length > 0 } {
HTTP::collect $content_length
}
}
}
when HTTP_RESPONSE_DATA {
log local0.info "Content Type: [HTTP::header Content-Type]"
if { ! ([HTTP::payload] contains $::exist_search) } {
log local0.info "Payload didn't contain $::exist_search!"
set idx [string last "" [HTTP::payload]]
if { -1 == $idx } {
set idx [string last "" [HTTP::payload]]
}
log local0.info "html end tag found at $idx"
if { -1 == $idx } {
log local0.info "-1 == $idx"
set offset [HTTP::payload length]
} else {
log local0.info "-1 != $idx"
set offset $idx
}
log local0.info "before HTTP::payload replace"
HTTP::payload replace $offset 0 $::analytics
log local0.info "after HTTP::payload replace"
}
}
when CLIENT_CLOSED {
Log the end time of the TCP connection
log local0.info "Closed TCP connection from [IP::client_addr]:[TCP::client_port] to [IP::local_addr]:[TCP::local_port] (open for: [expr [clock clicks -milliseconds] - $tcp_start_time]ms)"
}
when CLIENT_ACCEPTED {
Get time for start of TCP connection in milleseconds
set tcp_start_time [clock clicks -milliseconds]
Log the start of a new TCP connection
log local0.info "New TCP connection from [IP::client_addr]:[TCP::client_port] to [IP::local_addr]:[TCP::local_port]"
}
Logging
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : New TCP connection from XXX.XXX.XXX.XXX:20747 to XXX.XXX.XXX.XXX:443
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Client XXX.XXX.XXX.XXX:20747 -> www.hostname.com/my/uri.do?action=action1 (request)
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : HTTP::version = 1.1
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : is_keepalive = true
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Connection is now Keep-Alive
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : HTTP::version is now 1.0
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Client XXX.XXX.XXX.XXX:20747 -> www.hostname.com/my/uri.do?action=action1 (response) - pool info: was XXX.XXX.XXX.XXX 9443 - status: 200 (request/response delta: 247ms)
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Collecting 1000000000 bytes
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Content Type: text/html;charset=UTF-8
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : Payload didn't contain urchinTracker()!
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : html end tag found at 60866
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : -1 != 60866
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : before HTTP::payload replace
Nov 3 18:55:06 tmm tmm[2931]: Rule urchin_logger : after HTTP::payload replace
Nov 3 19:00:06 tmm tmm[2931]: Rule urchin_logger : Closed TCP connection from XXX.XXX.XXX.XXXX:20747 to XXX.XXX.XXX.XXX:443 (open for: 300568ms)
3 Replies
- Brad_53264
Nimbostratus
I found the root cause of my issue.
"SOL8648: An HTTP connection can stall if collecting a response using HTTP::collect and the response has no Content-Length header"
I am running version 9.4.3 with ASM. I've disabled ASM and the problem is now resolved. This known issue has been resolved in 9.4.5. - Brad_53264
Nimbostratus
Does anyone know a way to implement the same functionality without using HTTP::collect? - hoolio
Cirrostratus
That issue is fixed in 9.4.5 so upgrading should resolve the issue. As there have been a lot of significant issues fixed in 9.4.5HF2, it would be good to upgrade regardless of this issue.
I'm not sure why the server is responding with no content length header though if you're forcing HTTP 1.0. I thought the only time a server would use no content length header was if the HTTP version was 1.1 and the encoding was chunked.
You could insert the HTML using a stream profile and STREAM::expression iRule. It would probably be more efficient than buffering the response payload using HTTP::collect.
You could look for in the STREAM::expression and then replace the matched string with plus the HTML for the urchin. However, I'm not sure whether you would be able to only do the insertion if the "urchinTracker()" string isn't already present.
Take a look at the STREAM::expression (Click here) and STREAM_MATCHED (Click here) wiki pages for some examples to see if this could work for your scenario.
Aaron
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
