miércoles, 27 de agosto de 2014

Crea tu propio benchmarking de páginas web

El siguiente código en Python te permitirá realizar tus propios benchmarkings de páginas Web, simulando un escenario concurrente de muchos usuarios al mismo tiempo accediendo al mismo sitio Web. El resultado se almacena en un archivo de log que después podrá llevarse a una hoja de cálculo para calcular estadísticas de tiempos, o para identificar errores.

import time
import datetime
import urllib2
import logging
import threading
 
# Coleccion de urls a solicitar
urls = [
   'http://192.168.0.3/oiddigity_actual/index.html',
   'http://192.168.0.3/oiddigity_actual/registrado.asp',
   'http://192.168.0.3/oiddigity_actual/inicio.html',
   'http://192.168.0.3/oiddigity_actual/botones2.html',
   'http://192.168.0.3/oiddigity_actual/horafecha.asp'

 
# Nombre del fichero de log para guardar resultados
fich_log = 'testeo.log'
 
# Numero de hilos
num_hilos = 200
 
# Numero de procesos por hilo
num_procesos = 100
 
# Conteo de errores
num_errores = 0
 
# Metodo: proceso_urls()
# Procesa las urls, retornando el
# tiempo que consume
def proceso_urls():
   inicio = datetime.datetime.now()
   resultado = ""
 
   # Solicita y lee todas las urls
   for i in urls:
      try:
         peticion = urllib2.Request(i)
         respuesta = urllib2.urlopen(peticion)
         contenido = respuesta.read()
         resultado = "|OK"
         break
      except Exception as e:
         resultado = "|NOK[" + i + "]" + format(str(e))
 
   fin = datetime.datetime.now()
   tiempo = inicio.strftime("%T.%f")+'|'+fin.strftime("%T.%f")+"|"
   tiempo += get_tiempo(fin-inicio)
   tiempo += resultado
 
   return tiempo
 
# Metodo: get_tiempo()
# Retorna, a partir de un time, el tiempo en formato %H|%M|%S|%f
def get_tiempo(tiempo):
   resultado = ""
   segundos = tiempo.seconds
 
   if (segundos>=3600):
      horas = int(segundos/3600)
      resultado += str(horas) + "|"
   else:
      resultado += "0|"
 
   if (segundos>=60):
      minutos = int(segundos/60)
      resultado += str(minutos) + "|"
   else:
      resultado += "0|"
 
   resultado += str(segundos) + "|" + str(tiempo.microseconds)
 
   return resultado
 
# Metodo: proceso_hilo()
# Metodo principal del hilo
def proceso_hilo(count):
   global num_errores # Referencia a variable global compartida
 
   print 'Iniciando hilo ', count
 
   for i in range(num_procesos):
      resultado = proceso_urls()
 
      if (resultado.find("NOK") > 0):
         num_errores += 1
         print "#", num_errores, " > ", str(count), "[", str(i), "] > ", resultado
 
      logging.info(''+str(count)+"|"+str(i)+"|"+resultado)
 
   print 'Hilo', count, 'finalizado'
 
 
# Configuracion del fichero de log
logging.basicConfig(filename=fich_log, filemode='w', level=logging.DEBUG)
# Cabecera del log
logging.info('Hilo|Proceso|Inicio|Fin|Horas|Minutos|Segundos|Milisegundos|Resultado')
 
print '----------------------------------'
print 'Testeo. 2014 by Rafael Hernamperez'
print '----------------------------------'
print 'URLs a testear:'
 
for i in urls:
   print ' - ', i
 
print '> Ejecutando ', num_hilos, ' hilos'
print '> Total procesos: ', num_hilos * num_procesos
 
# Genera los hilos y los ejecuta
threads = list()
 
for i in range(num_hilos):
   t = threading.Thread(target=proceso_hilo, args=(i,))
   threads.append(t)
   t.start()

La variable urls permite definir las urls que van a solicitarse. Una página web puede tener varios iframes incluyendo otras partes de código web (otras páginas o servicios), las cuales han de invocarse para tener tiempos reales.

La variable fich_log define el nombre del fichero de log, en el cual se volcarán todos los resultados.

La variable num_hilos define el número de conexiones concurrentes. Esto simulará el escenario de n usuarios accediendo al mismo tiempo a las urls definidas.

La variable num_procesos define el número de veces que cada hilo llamará a las urls definidas.

La variable num_errores recoge el número de errores que se pueda producir durante el testeo.

El método proceso_urls() solicita las urls definidas y leyendo las respuestas por parte del servidor web. Tras el proceso guarda en el log el resultado con los tiempos y los posibles errores.

El método get_tiempo() retorna un literal con la descomposición del tiempo que se pasa por parámetro. Este literal se utiliza para el log, y es invocado por proceso_urls() para obtener el desglose del tiempo que ha tardado el proceso en ejecutarse.

El método proceso_hilo() es utilizado por cada uno de los hilos para lanzar todos los procesos definidos en la variable num_procesos. Es decir, repite num_procesos veces el acceso a las urls definidas.

Por último, para hacer funcionar esta aplicación, crea un fichero llamado (por ejemplo) testeo.py, copia y pega el código, guárdalo y ejecútalo desde la consola o terminal mediante el comando:

$ python testeo.py