El otro día necesitaba saber si había alguna/s IP/s que estuvieran haciendo muchos requests a un dominio, así que escribí un muy sencillo script en Python para obtener la cantidad de peticiones por IP en un access_log de Apache. Se los dejo por si a alguien le sirve. Se me ocurre que con bash y las distintas herramientas de unix para manipular archivos y strings quizás habría podido hacer algo un poco más óptimo (aunque esto anda bastante rápido), pero me sentía más cómodo con Python.
Script
#!/usr/bin/python
import sys
from operator import itemgetter
file = open(sys.argv[1], "r")
ips = {}
line = None
while line != "":
line = file.readline()
ip = line.rsplit(" ")[0]
if ip != "":
if ips.has_key(ip):
ips[ip] = ips[ip] + 1
else:
ips[ip] = 1
file.close()
list = sorted(ips.items(), key=itemgetter(1), reverse=True)
for item in list:
print item[0].rjust(15, " "), ": ", item[1]
Cómo usarlo
Guardar el script en un archivo por ejemplo countip.py. Luego darle permisos de ejecución y correrlo.
# chmod +x countip.py # ./countip.py /var/log/httpd/access_log
Según mis pruebas el script procesa un log de más de 14 mil líneas en aproximadamente 0,09 segundos.

Por cierto, el script está pensado para contar la cantidad de requests por IP de un access_log de Apache, pero en realidad es bastante más genérico que eso. Lo que hace es tomar la primer palabra (primer conjunto de caracteres sin espacios) de cada línea del archivo e ir sumando la cantidad de ocurrencias de cada palabra nueva en un diccionario. Por lo tanto se puede usar para cualquier otro fin similar.
No es mas facil matchear las ips con una regexp y despues contarlas?:p
Habría que probarlo, pero creo que no sería igual de óptimo en términos de performance. Porque creo que eso lo podrías hacer de dos formas, hacer un script con la misma lógica que el mío (recorriendo cada línea y aplicando la regexp a la línea, e ir sumando), o aplicando una regexp a todo el log con la cual extraigas las IPs y luego contarlas.
En este segundo caso el procedimiento implicaría lo siguiente:
- Compilar la regexp
- Leer todo el log y almacenarlo en una variable
- Aplicar la regexp y obtener un array con todas las IPs
- Recorrer el array para contar la cantidad de ocurrencias de cada IP distinta
- Mostrar los resultados
En los dos casos el hecho de compilar la regexp te agrega un overhead de procesador que yo evito asumiendo que sí o sí la primer palabra de cada línea es la IP. En el segundo caso además agregás el hecho de tener una variable enorme con todo el contenido del archivo en memoria (si el archivo es muy grande puede ser problemático), lo cual yo evito sobreescribiendo el buffer donde voy almacenando cada línea, en cada loop del while. A eso se sumaría después otro array bastante grande con todas las IPs matcheadas.Y luego se agrega el paso de recorrer el array para encontrar IPs repetidas, el cual yo evito al hacerlo mientras voy leyendo el archivo.
Otra forma de hacerlo sería con awk, sort y uniq, por ejemplo así:
awk ‘{print $1}’ access_log|sort|uniq -c|sort -nr
Una ventaja que tiene este método es que tarda la mitad que con python en procesar el fichero.
Un saludo
De hecho es lo que hice en el post que escribí después de este:
http://www.tail-f.com.ar/programacion/bash/contar-requests-por-ip-de-un-access_log-de-apache-en-bash.html