Frecuentemente me encuentro ante la necesidad de saber qué dominios de los que tengo alojados en mis servidores consumen más tráfico HTTP. Como éste es el tipo de tráfico más importante y que más incide en el desempeño general de mis servidores, saber qué dominios transfieren más datos por HTTP me orienta en la búsqueda de heavy users. Para ello hice un script hace algún tiempo, y ahora lo estuve revisando, retocando y simplificando, y decidí compartirlo.
En el entorno de Directadmin, los logs de Apache se encuentran en /var/log/httpd. Allí hay una carpeta “domains” que guarda los logs de cada dominio. Por cada dominio hay tres logs: dominio.com.log, dominio.com.error.log y dominio.com.bytes. El primero es el access_log, el segundo el error_log y el tercero solamente guarda la cantidad de bytes de cada request. La opción más sencilla es trabajar con este último tipo de logs, pero el problema que tienen es que no indican la fecha. Si bien se supone que los logs de Directadmin rotan una vez por día, alguna vez me ha pasado que por razones que nunca pude descubrir, algunos logs no rotaban y generaban ciertas confusiones. Por lo tanto, el script que dejo usa los access_logs. Además esta opción es reutilizable en otras implementaciones de Apache que no tengan archivos de bytes.
El código:
#
# Parses all the files in a directory
# treating them as access_log files
# and outputs the list of files sorted
# by transfered megabytes. Useful for
# identifying heavy users.
#
# Usage:
# ./access_log_parser.sh <base_dir>
# base_dir = directory where the access_log files are
if [ -z $1 ]; then
echo "Usage: $0 "
exit 1
fi
BASE_DIR=$1
T1=`date +%s`
for file in $BASE_DIR/*;
do
size=`stat -c %s $file`
if [ $size -gt 0 ]; then
from=`head -1 $file | awk ‘{print($4)}’ |sed ‘s/^\[//’`
to=`tail -1 $file | awk ‘{print($4)}’ |sed ‘s/^\[//’`
bytes=`cat $file | awk ‘{a+=$10}END{print a}’`
mbytes=`echo $bytes | awk ‘{print $1 / 1048576}’`
echo "$mbytes MB ($bytes bytes) | From: $from | To: $to | ${file:${#BASE_DIR}+1}"
fi
done \
| sort -nb
T=`date +%s`
Un detalle importante: el script levanta todos los archivos de un directorio que se especifica por parámetro. Esto es así porque yo lo invoco desde otro script:
LOG_DIR=/var/log/httpd/domains/
TMP=/tmp/domain_logs
if [ ! -d $TMP ]; then
mkdir -p $TMP
fi
rm -f $TMP/*
cd $LOG_DIR
for i in `ls *.log |grep -v error`; do
ln $i $TMP/$i
done
/root/access_log_parser.sh $TMP
Este último script lo que hace es crear un directorio temporal (si no existe). Vaciar su contenido. Y luego generar hardlinks a todos los access_logs de /var/log/httpd/domains. De esta forma, no me tengo que preocupar por si los logs son modificados mientras yo estoy ejecutando el script. Por último, ejecuta mi primer script (access_log_parser.sh) y le pasa como parámetro el directorio temporal donde están los access_logs.
Por último, la salida del script sería algo así:
... 186.995 MB (196078184 bytes) | From: 10/Mar/2010:00:27:47 | To: 10/Mar/2010:16:51:09 | dominio1.com.ar.log 187.096 MB (196184596 bytes) | From: 10/Mar/2010:03:24:55 | To: 10/Mar/2010:16:51:24 | dominio2.com.ar.log 245.692 MB (257626221 bytes) | From: 10/Mar/2010:02:53:50 | To: 10/Mar/2010:16:39:54 | dominio3.com.log 273.46 MB (286743390 bytes) | From: 10/Mar/2010:02:48:33 | To: 10/Mar/2010:14:59:29 | dominio4.com.ar.log 306.344 MB (321224473 bytes) | From: 10/Mar/2010:00:23:09 | To: 10/Mar/2010:16:51:20 | dominio5.com.ar.log 444.097 MB (465669066 bytes) | From: 10/Mar/2010:00:49:35 | To: 10/Mar/2010:16:51:20 | dominio6.com.ar.log Generated in 6 seconds
Les dejo, de yapa, la opción del script utilizando los logs de bytes. Como dije, esta opción es un poco más sencilla y veloz, pero no nos dice las fechas de los logs.
if [ -z $1 ]; then
echo "Usage: $0 "
exit 1
fi
BASE_DIR=$1
T1=`date +%s`
for file in $BASE_DIR/*.bytes;
do
size=`stat -c %s $file`
if [ $size -gt 0 ]; then
bytes=`cat $file | awk ‘{a+=$1}END{print a}’`
mbytes=`echo $bytes | awk ‘{print $1 / 1048576}’`
echo "$mbytes MB ($bytes bytes) ${file:${#BASE_DIR}+1}"
fi
done \
| sort -nb
T=`date +%s`
echo "Generated in $(($T-$T1)) seconds"
Y la salida sería así:
# ./parser.sh /var/log/httpd/domains ... 181.716 MB (190543470 bytes) dominio1.com.bytes 187.115 MB (196203973 bytes) dominio2.com.ar.bytes 189.093 MB (198278283 bytes) dominio3.com.ar.bytes 245.692 MB (257626221 bytes) dominio4.com.bytes 273.472 MB (286756234 bytes) dominio5.com.ar.bytes 314.32 MB (329588717 bytes) dominio6.com.ar.bytes 444.516 MB (466108759 bytes) dominio7.com.ar.bytes Generated in 2 seconds
0 Comentarios.