In a high-availability web environment there are typically HTTP load balancers like HAProxy, or reverse proxies like Apache or Nginx, sitting in front of the application servers to spread the load and/or filter some requests.
The main problem with this kind of architecture is that the front-end web service usually masks the source IP of the client, reducing traceability on the backends. This article assumes that the front-end web service forwards the IP to the backend via an HTTP header called X-Real-IP.
The trick shown here lets you log the client IP via the X-Real-IP header when it is present, otherwise fall back to the source IP.
First, define two LogFormats, complete_realip and complete, each with a different first field:
LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\" %D" complete_realip
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\" %D" complete
Next, use the mod_setenvif module to test for the existence of the header:
SetEnvIf X-Real-IP ^.+$ real_ip_exists
Finally, set up an environment-based condition so the log switches between the two formats depending on the incoming request:
CustomLog /var/log/apache/myapp_access.log complete_realip env=real_ip_exists
CustomLog /var/log/apache/myapp_access.log complete env=!real_ip_exists
Your Apache server will now dynamically switch the IP it logs depending on whether the X-Real-IP header is present.
Note: if you use HAProxy in front, add the following configuration to your HAProxy backends:
http-request set-header X-Real-IP %[src]