Analizando los Logs del Apache con PHP (I)
Para manejar perfectamente un servidor Web, es necesario obtener información sobre la actividad
y estado del servidor así como de cualquier problema que esté ocurriendo.
El servidor Web de Apache proporciona unas capacidades de recopilación de información (logs)
muy sencillas, flexibles y comprensivas.
En estas 2 secciones de este mini manual voy a tratar de explicar como realizar un analizador de logs del servidor Web Apache.
En la primera sección trataré acerca de los ficheros de logs del Apache, para irnos familiarizando con ellos, mientras que en la segunda
trataré como montar un analizador de logs en PHP.
El fichero de Logs
El fichero de logs de acceso graba todas las peticiones procesadas por el servidor
en una serie de registros. La localización y el contenido del fichero de los logs
son controlados por la directiva CustomLog. El formato de la directiva LogFormat
puede ser utilizado para simplificar la selección de contenidos de los logs.
Voy a empezar describiendo como configurar el servidor para guardar la información de los
logs de acceso.
Por su puesto, guardar la información en el fichero de logs de acceso es sólo el comienzo,
posteriormente habrá que poder analizar toda esa información para producir estadísticas útiles.
El formato de los logs de acceso es altamente configurable. El formato se especifica usando una cadena de texto formateada del estilo al de los
formatos de las cadenas formateadas que se especifican en la función printf de C.
Formato de logs
Existen 2 formatos más o menos estandares, el Common y el Combined. Yo he preferido el combined
porque da mucho más juego.
Una configuración típica para los logs de acceso puede parecerse a lo siguiente:
LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog logs/access_log common
La primera cadena define el apodo common y lo asocia con una cadena formateada
particular. Esta cadena formateada consta de directivas de porcentaje, cada una de las cuales
le dice al servidor que información deberá almacenar.
Los caracteres literales podrán ser introducidos en cualquier lugar de la cadena formateada y serán posteriormente copiados en la salida de los logs. El carácter comilla doble (“) debe ser escapado por una barra back-slash (\) para prevenir que se entienda como el final de la cadena formateada. Esta cadena puede contener además caracteres de control como “\n” para una nueva línea y “\t” para el tabulador.
La directiva CustomLog establece un nuevo fichero de logs, utilizando el apodo
establecido. El nombre del fichero para el fichero de los logs de acceso es relativo al
directorio ServerRoot a menos que comience con la barra del 7 (/).
La siguiente configuración escribirá entradas en el fichero de logs en un formato conocido
como Common Log Format (CLF). Este formato estándar puede ser producido por diversos
servidores Web, leídos y analizados por muchos programas de análisis.
Una entrada CLF producida en el fichero de logs puede ser parecida a la siguiente:
127.0.0.1 - deckerix [10/Oct/2004:13:55:36 -0700] "GET /mi_foto.png HTTP/1.0" 200 2326
Cada sección de la cadena anterior se describe a continuación:
127.0.0.1 (%h)
Esta es la dirección IP del cliente (host remoto) que realiza la petición al servidor. Si la directiva HostnameLookups está activada (puesta a ON), el servidor intentará determinar el nombre del host y sustituirlo en lugar de almacenar la IP. Sin embargo, esta configuración no es recomendada ya que puede ralentizar al servidor. En su lugar, es mejor utilizar un programa post-proceso que determine los nombres de los hosts. La dirección IP guardad no tiene porque ser necesariamente la de la maquina que realiza la petición. Si existe un servidor proxy entre el usuario y el servidor, esta dirección será la del proxy en lugar de la de la máquina original.
- (%l)
El guión en la salida indica que la petición de la una determinada información no está disponible. En este caso, la información que no está disponible es la identidad del RFC 1413 determinado a partir del identd en las máquinas clientes. Esta información tiene bastante poco valor, y no debería ser nunca usada, excepto en algunas excepciones donde se lleve un rigurosísimo control de las intranets. El servidor Apache httpd no intentará determinar esta información a no ser que la directiva IdentityCheck se encuentre active (On).
deckerix (%u)
Este es el identificador del usuario que pide el documento tal y como la autenticación HTTP puede determinar. Este valor suele ser tomado por los scripts CGIs en la variable de entorno REMOTE_USER . Si el código de estados para la petición es 401, entonces este valor no es adecuado ya que el usuarios no ha sido autentificado. Si el documento no tiene protección mediante password, esta entrada será “-” como el anteriormente comentado.
[10/Oct/2000:13:55:36 -0700] (%t)
La hora en la cual el servidor terminó de procesar la petición. El formato es:
[día/mes/año:hora:minuto:segundos zona]
día = 2*digitos mes = 3*caracteres (iniciales inglesas) año = 4*digitos hor = 2*digitos minuto = 2*digitos segundos = 2*digitos zona = (`+' | `-') 4*dígitos
Es posible mostrar la hora en otro formato modificando la cadena de formato especificando
la directiva %{formato}t , donde el formato se especifica como en la función strftime(3) de C.
"GET /apache_pb.gif HTTP/1.0" (\"%r\")
La línea de petición del cliente se muestra entre comillas dobles. La línea de petición contiene un información muy útil. Primero, el método usado por el cliente es GET. Segundo, el cliente ha pedido al servidor el recurso /apache_pb.gif, y tercero, el cliente usa el protocolo http/1.0. Es también posible registrar una o mas partes de la línea de petición independientemente. Por ejemplo, la cadena formateada “%m %U%q %H” registrará el método, el path, la query-string y el protocolo, (misma salida que “%r”).
200 (%>s)
Este es el código de estado que el servidor devuelve el cliente por cada petición. Esta información es muy valiosa. Porque revela si la petición a tenido éxito (códigos que comienzan por 2), si se ha realizado una redirección (códigos que comienzan por 3), ha surgido un error provocado por el cliente (códigos que comienzan por 4), o ha surgido un error en el servidor (códigos que comienzan por 5). La lista de todos los posibles códigos de estado se puede encontrar en las especificaciones del protocolo HTTP (RFC2616 sección 10).
2326 (%b)
La última entrada indica el tamaño del recurso enviado hacía el cliente, sin incluir las cabeceras de respuesta. Si ningún contenido es enviado al cliente, tendrá el valor “-“. Para registrar “0” para este caso habrá que usar mejor “%B”.
Como comentaba antes, otra cadena de formato bastante utilizada es una denominada “Combined”.
Esta se utiliza como se muestra a continuación.
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined CustomLog log/access_log combined
Este formato es exactamente el mismo que el Common, con la adición de 2 campos nuevos. Cada uno de ellos usa la directiva porcentual %{header}i, donde header puede ser cualquier cabecera de petición HTTP. El registro de logs bajo este formato tomará este aspecto:
127.0.0.1 - deckerix [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"
Los campos adicionales son:
"http://www.example.com/start.html" (\"%{Referer}i\")
La cabecera de petición del “Referer”. Esto da la información sobre que enlace a usado el usuario para llegar a nuestro recurso (de donde procede). En este caso desde donde se pidió /mi_foto.gif.
"Mozilla/4.08 [en] (Win98; I ;Nav)" (\"%{User-agent}i\")
La cabecera de petición para el Agente de usuario (User-Agent http). Esta es la información de la identificación del navegador o cliente que realiza la petición al servidor.
Tabla de códigos de estado del protocolo HTTP 100 Continue Continua 101 Switching Protocols Intercambiando protocolos 200 Ok Solicitud enviada correctamente 201 Created Creado 202 Accepted Todavía está en proceso 203 Non-Authoritative Information Información no autoritativa 204 No Content No contenido 205 Reset Content Reset contenido 206 Partial Content Contenido parcial 300 Multiple Choices Múltiples opciones 301 Moved Permanently Movido permanentemente 302 Found Localizado en otro sitio 303 See Other Ver otro 304 Not Modified No Modificado 305 Use Proxy Usa Proxy 306 (Unused) (Unused) 307 Temporary Redirect Redirección temporal 400 Bad Request Solicitud incorrecta 401 Unauthorized Documento restringido 402 Payment Required Documento restringido 403 Forbidden Privilegios insuficientes 404 Not Found Documento no encontrado 405 Method Not Allowed Mé;todo no permitido 406 Not Acceptable No acceptable 407 Proxy Au Authentication Required Requerida autenticación proxy 408 Request Timeout Timeout petición 409 Conflict Conflicto 410 Gone Gone 411 Length Required Longitud requerida 412 Precondition Failed Precondición fallida 413 413 Request Entity Too Large Request Entidad demasiado grande 414 Request-URI Too Long URL demasiado larga 415 Unsupported Media Type Media type no soportado 416 Requested Range Not Satisfiable Requested Range no Satisfiable 417 Expectation Failed Expectación fallida 500 Internal Error Error interno en el servidor 501 Not Implemented No implementado 502 Bad Gateway Gateway Erroneo 503 Service Unavailable Servicio No disponible 504 Gateway Timeout Gateway Timeout 505 HTTP Version Not Supported Versión protocolo http no soportado
Se pueden configurar muchas otras cosas, como realizar logs condicionales, o mantener diferentes registros en
ficheros diferentes, etc. Si quereis saber más, podeis acceder a la web de Apache donde tratan acerca de los Logs del servidor