|
Generación de archivos de log personalizados
Salvo que las páginas hospedadas en su servidor web
Apache sólo las vaya a ver usted, las pueda ver más
gente pero no reciba ninguna visita, o simplemente no le interese saber quién,
cuándo, cómo y desde dónde son visitadas, seguro que le interesará saber
que Apache dispone de numerosas posibilidades para registrar
información sobre las visitas a su sitio web.
Si procesamos los registros o logs generados por el servidor
Apache con alguno de los múltiples y variados programas
analizadores de logs disponibles (tanto gratuitos como de pago)
además de tener constancia de todas las visitas podremos ver estadísticas diversas,
como páginas más visitadas, lugares del mundo donde es más popular nuestro
sitio, en qué franjas horarias recibimos más visitantes, o el porcentaje de uso de
cada navegador web entre los visitantes de nuestro sitio.
Entre otros programas analizadores de log tenemos algunos libres (y
gratuitos), con diversos niveles de complejidad, velocidad, profusión de
estadísticas y vistosidad. Desde analog a
awstats, pasando por
webalizer, cualquier analizador de
logs que entienda el formato CLF
(Common Log Format) servirá para obtener estadísticas
de visitas a nuestra web.
Pero Apache no sólo puede generar registros de visitas en
este formato, sino en cualquier formato que desee el administrador, puesto que el contenido y tipo
de las visitas que se registran son completamente configurables por el administrador. Es más,
podemos tener archivos de log personalizados para cada uno de los
diferentes virtual hosts que albergue nuestro servidor, o tener
varios archivos de log cada uno de los cuales contenga
información específica de algún detalle de la visita, etc.
En Apache, sin embargo, disponemos de un tipo especial de archivo
de log que no es personalizable: el archivo de errores, definido por
la directiva ErrorLog. Si bien tenemos la posibilidad de crear un
archivo de errores por cada virtual host no podemos influir en el
formato de la información que se registra en él, puesto que contiene los errores de
inicio y en tiempo de ejecución tanto de Apache como de los
posibles módulos cargables en uso, o la ejecución de los programas CGI.
Para personalizar los logs que genera Apache
contamos principalmente con dos directivas de configuración: la directiva
LogFormat (permite definir un formato personalizado, es decir,
qué información se registra en cada petición de página), y
CustomLog (permite definir un nuevo archivo de
log donde se almacene la información definida en una
directiva LogFormat previa). Es decir, separamos los conceptos de
archivo de log (CustomLog) y la
información que registramos cuando se nos pide una página, o formato del archivo
(LogFormat).
Como puede comprobar en el archivo de configuración de Apache
(típicamente /etc/apache/httpd.conf) ya están definidos
de manera predeterminada algunos formatos de log:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %T %v" full
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %P %T" debug
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-Agent}i" agent
Los más habituales son los cuatro últimos, especialmente el
LogFormat de nombre common, puesto que se
corresponde con el formato CLF mencionado antes, y es el que entienden todos los programas
analizadores de logs del mercado (algunos analizadores entienden
más formatos, o son personalizables, pero todos entienden el formato CLF). El formato de
la directiva incluye la información que registrar (indicada mediante las
magic cookies precedidas por el signo %),
y el nombre que le damos al formato, nombre que será el que usemos posteriormente en tantas
directivas CustomLog como queramos. Dese cuenta también de que
el formato llamado combined incluye la información de los formatos
common, referer y agent.
Si echa un vistazo a la lista de
cookies soportadas verá qué significa cada campo
de las directivas LogFormat anteriores. Por ejemplo, la
cookie %h registrará la
dirección IP del cliente, y %{User-Agent} la
identificación del navegador que usa (consulte
este artículo para saber algo
más sobre el funcionamiento del protocolo HTTP).
Pero con las directivas LogFormat sólo hemos definido varios
formatos de información que podemos registrar ante cada petición de página,
pero no hemos indicado a Apache que realmente la guarde en disco. Para
ello debemos usar una o más directivas CustomLog, tanto en la
configuración global del servidor (aplicará al servidor predeterminado) como en cada
uno de los virtual hosts donde queramos personalizar los
logs. Por ejemplo:
CustomLog /var/log/apache/access.log combined
<VirtualHost 192.168.1.101:80>
ServerName www.example.com
DocumentRoot /var/www/example.com
DirectoryIndex index.html
CustomLog /var/log/apache/example.com_common.log common
CustomLog /var/log/apache/example.com_useragent.log agent
</VirtualHost>
Estos archivos de log definidos arriba comenzarán a guardar
la información correspondiente en cuanto se señalice al proceso principal de
Apache. Y cuando contengan datos de acceso ya los podríamos
procesar con la utilidad de estadísticas web de nuestra
elección. Pero a´n cabe la posibilidad de tener más control sobre la
información registrada en disco, por ejemplo, decidiendo petición por petición
si guardamos información de la misma en función de determinados parámetros de
la propia petición (por ejemplo, sólo nos interesa conocer qué navegadores usan
los usuarios que acceden a una determinada parte de la web).
Para hacer este registro condicional de la información necesitamos conocer otra directiva
de Apache, la directiva SetEnvIfNoCase.
Como su propio nombre indica, esta directiva establece una determinada variable de entorno si la
petición HTTP recibida cumple un determinado patrón,
evaluado sin distinguir entre mayúsculas y minúsculas (existe una directiva
SetEnvIf, igual que la anterior pero donde el patrón se evalua
distinguiendo entre mayúsculas y minúsculas).
La directiva CustomLog dispone de un parámetro opcional
adicional a los ya vistos, que es la especificación de una variable de entorno que, de
estar presente, hace registrar a disco la información definida por el
LogFormat correspondiente. Si la variable de entorno indicada no
está presente (por ejemplo, porque la petición no coincida con el patrón
indicado en una directiva SetEnvIfNoCase previa), esa petición
no se registrará en ese archivo de log (aunque bien pudiera
registrarse en otro archivo distinto, con otro formato distinto).
Lo explicado en los párrafos previos se verá mucho más claro con un ejemplo
práctico: desde principios del año 2003 Telefonica ha
colocado dispositivos de proxy caché para los usuarios de
líneas ADSL, en teoría para mejorar la velocidad de la navegación. Sin embargo,
por cómo funciona el mecanismo de proxy, la dirección
IP que ve nuestro servidor web no es la del usuario final, sino la
del dispositivo que hace de proxy. Si este dispositivo da servicio
a muchos usuarios que acceden a nuestras páginas, aparecerán todos estos accesos
como provenientes desde la IP del proxy, no de los usuarios
individuales. Parece evidente que en webs cuyo público
mayoritario sea residente en España las estadísticas de acceso quedarán
completamente desvirtuadas.
Lo que sucede es que en el caso de conexiones llegadas a través de un
proxy, la cookie
%h no contiene la IP del usuario final, sino la del dispositivo de
proxy. Para evitar este problema de alguna manera tenemos que
conseguir que Apache genere las entradas de
log de manera distinta en función de si la petición
llega directamente desde el usuario final, o a través de un proxy
intermedio.
Afortunadamente los proxy comunican al servidor
web la dirección IP del cliente en cuyo nombre están
pidiendo la página. Para ello suelen enviar las cabeceras HTTP
Client-IP y X-Forwarded-For en la
petición de la página, variables cuya existencia y contenido podemos comprobar desde
las directivas SetEnvIfNoCase. La idea será usar esta directiva
para establecer una cierta variable de entorno cuando la petición provenga de un
proxy, y luego tener dos CustomLog
diferentes, uno el habitual (para conexiones directas) y otro donde sustituyamos la
cookie %h por el contenido de alguna de
las cabeceras con la dirección IP del cliente enviadas por el proxy.
# Sólo las peticiones de un proxy contendrán una dirección IP en Client-IP
SetEnvIfNoCase Client-IP "\." proxy
# Formato predeterminado de los logs CLF
LogFormat "%h %l %u %t \"%r\" %>s %b" common
# Definimos un formato de log especial para peticiones desde proxy
LogFormat "%{Client-IP}i %l %u %t \"%r\" %>s %b" common_proxy
# Las peticiones directas desde los clientes, con el formato habitual
CustomLog /var/log/apache/access.log common env=!proxy
# En las peticiones desde los proxy, usamos el formato alternativo
CustomLog /var/log/apache/access.log common_proxy env=proxy
Con la directiva SetEnvIfNoCase definimos una variable de entorno para
las peticiones que contienen una cabecera Client-IP (en realidad
miramos si el valor de la cabecera contiene un punto, lo cual sólo se cumple si la cabecera
existe y contiene una dirección IP). Luego definimos un formato personalizado de
log donde usamos el contenido de la cabecera
HTTP Client-IP en lugar de el contenido
de la cookie %h, que en el caso de un
proxy contiene su dirección IP, no la del usuario final. Por
último, guardamos la información de acceso en el formato correspondiente a
peticiones directas (env=!proxy significa
"variable proxy no definida") y a peticiones a través de
proxy (env=proxy).
Fíjese que estamos guardando ambos tipos de información en el mismo archivo en
disco: si bien la documentación de Apache no dice nada al
respecto de si esto se puede hacer o no, el caso es que funciona, incluso en situaciones donde se
guarda información simultáneamente en ambos formatos (en nuestro ejemplo puesto
que la petición es directa o indirecta, sólo se generará una entrada de
log en el archivo por cada petición de página). Otra
opción sería guardar a dos archivos diferentes, y antes de procesarlos con nuestra
herramienta de generación de estadísticas, unirlos (podría ser suficiente
concatenarlos con un simple comando cat).
En este ejemplo hemos usado la cabecera HTTP
Client-IP, puesto que si la petición proviene de un
proxy contendrá la dirección IP del
navegador del usuario. Por su parte, en la cabecera X-Forwarded-For se
incluyen las IP de todos los proxy en el camino de la petición
del usuario desde su navegador al servidor, y en situaciones con más de un
proxy intermedio contendrá más de una
dirección. A día de hoy desconozco si la anterior configuración de
Apache funciona correctamente, entre otras cosas porque no estoy
seguro de en qué cabecera HTTP los
proxy están obligados a incluir la dirección IP del
usuario al cual dan servicio (además de la cabecera Client-IP
también está la cabecera Remote-Addr, por ejemplo).
Una manera de solucionar el problema potencial descrito en el párrafo anterior
consistiría en definir tantas ternas de directivas SetEnvIfNoCase,
LogFormat y CustomLog como posibles cabeceras
puedan contener la IP real del cliente. Pero en tal caso también deberíamos
modificar el CustomLog predeterminado, para que sólo aplique
cuando la petición de página sea directa, por ejemplo, estableciendo una variable de
entorno con SetEnvIfNoCase para todas las peticiones sin cabecera
X-Forwarded-For. Evidentemente todo esto es demasiado laborioso como para
exponerlo aquí, y posiblemente haya soluciones mucho mejores para hacer lo mismo, así
que se deja como ejercicio al lector :-).
Última modificación: 25-February-2003 18:21:49 -0500
|