Since we rely so heavily on the load balancers to handle part of the application logic the line between application servers and network equipment is blurred out. URIs and headers may change, and pools might be chosen depending on many different factors.

To add some transparence here I would recommend using the loadbalancer to give the users of your company additional information if they need it.

The iRule below would add the following informational response headers to requests originating from the data group list “office_public_ips”:

X-Virtual-Server-Name: /Partition/virtualserver-443
X-Original-Host: www.facebook.com
X-Host-Sent-To-Server: internal.facebook.com
X-Original-URI: /profile
X-URI-Sent-To-Server: /internal/profile
X-Selected-Pool: /Partition/MyPool-80_pool
X-Active-Members: 4
X-Selected-PoolPort: 80
X-Selected-Server: 192.168.1.20
X-Member-Status: 192.168.1.20 80 up;192.168.1.21 80 up;192.168.1.22 80 up;192.168.1.23 80 up;
X-TimeTaken-BigIP: 2
X-TimeTaken-Server: 53

It deserves some brush up but has been servicing us well for almost a year now. Don’t use it if you’re using web acceleration profiles (ram caching).

                                                                                                                                                                                                                    #Troubleshooting iRule
when CLIENT_ACCEPTED {

	set originaluri ""
	set urisenttoserver ""
	set originalhost ""
	set hostsenttoserver ""
	set chosenpool ""
	set memberstatus ""

	if { [class match [IP::remote_addr] equals office_public_ips] } {
		set internal 1
	} else {
		set internal 0
	}

}

when HTTP_REQUEST {
	if { $internal eq 1 } {
		set httpreqstarttime [clock clicks -milliseconds]
		set originaluri [HTTP::uri]
		set originalhost [HTTP::host]
	}
}

when LB_SELECTED {

	set selectedpool [LB::server pool]
	set selectedserver [LB::server addr]
	set selectedport [LB::server port]
	set memberstatus ""

	#Get the members of the currently selected pool
	set mbrs [members -list $selectedpool]

	#Get the status for each member
	foreach mbr $mbrs {
		set mbrlist [split $mbr " "]
		set memberip [lindex $mbrlist 0]
		set memberport [lindex $mbrlist 1]
		set status [LB::status pool $selectedpool member $memberip $memberport]
		set memberstatus "$memberstatus$mbr $status;"
	}

}

when HTTP_REQUEST_RELEASE {
	if { $internal eq 1 } {
		set urisenttoserver [HTTP::uri]
		set hostsenttoserver [HTTP::host]
	}
}

when HTTP_REQUEST_SEND {
	if { $internal eq 1 } {
		set httpreqsenttime [clock clicks -milliseconds]
	}
}

when HTTP_RESPONSE {
	if { $internal eq 1 } {
		set timetakenserver [expr {[clock clicks -milliseconds] - $httpreqsenttime}]
		HTTP::header insert X-TimeTaken-Server "$timetakenserver"
		HTTP::header insert X-Original-URI $originaluri
		HTTP::header insert X-URI-Sent-To-Server $urisenttoserver
		HTTP::header insert X-Virtual-Server-Name [virtual name]

		if { $selectedpool eq "" } {
			HTTP::header insert X-Selected-Pool "No pool selected"
		} else {
			HTTP::header insert X-Selected-Pool $selectedpool
			HTTP::header insert X-Active-Members [active_members $selectedpool]
		}

		if { $selectedserver eq "" } {
			HTTP::header insert X-Selected-Server "No server selected"
		} else {
			HTTP::header insert X-Selected-Server $selectedserver
		}

		if { $selectedport eq "" } {
			HTTP::header insert X-Selected-Port "No port selected"
		} else {
			HTTP::header insert X-Selected-Port $selectedport
		}

		if { $memberstatus eq "" } {
			HTTP::header insert X-Member-Status "No members"
		} else {
			HTTP::header insert X-Member-Status $memberstatus
		}


		HTTP::header insert X-Original-Host $originalhost
		HTTP::header insert X-Host-Sent-To-Server $hostsenttoserver
	}
}

when HTTP_RESPONSE_RELEASE {
	if { $internal eq 1 } {
		set timetakenbigip [expr {[clock clicks -milliseconds] - $httpreqstarttime - $timetakenserver}]
		HTTP::header insert X-TimeTaken-BigIP "$timetakenbigip"
	}
}