[TIP] Formatea la salida JSON de CURL

Si estas acostumbrado a trabajar con JSON, backends y demás palobrotos seguro que habrás usado cURL para obtener paquetes JSON.

La salida que cURL da no viene formateada, simplemente la muestra tal y cómo el backend lo devuelve.

Si el paquete que esperas tiene un cierto tamaño, esto puede ser un poco lioso.

El módulo de Python json tiene una utilidad para formatear JSON, luego me he creado una función BASH que añado a mi .bashrc y que me ahorra fallos y dolores de cabeza.

function jcurl() { curl $@ | python -m json.tool; }

Para añadir esta función a tu .bashrc

 echo "function jcurl() { curl \$@ | python -m json.tool; }" >> ~/.bashrc

Medir el tiempo de respuesta de Django

Midiendo tiempos de respuesta en Django

Midiendo tiempos de respuesta en Django

El tiempo de respuesta de un servicio web es el tiempo que transcurre desde que se realiza una petición hasta que se envía el último byte de respuesta al cliente.

Es vital para las aplicaciones web medir este tiempo con el objeto de optimizar la capacidad de respuesta. Nos interesa por tanto minimizar el tiempo de respuesta.

Para aplicaciones web desarrolladas con el framework Django he desarrollado un middleware sencillo que mide el tiempo de respuesta de proceso desde que Django es «consciente» (Python).

Sin duda el middleware, es una de las características que más me gusta de Django. Permite, entre otras tantas cosas, añadir objetos al request.

Una clase middleware debe tener al menos un método: process_request.

En nuestro caso, tenemos 3 métodos: process_request, process_response y __init__.

La idea es simple. Cuando llega un request, añadimos una marca de tiempo al request (process_request).

Cuando ese request es procesado, obtenemos la diferencia de tiempo y la «logueamos» (process_response).

En __init__ simplemente inicializamos el contexto de logging.

Os dejo el código.

¡Que aproveche! 🙂

import logging
from datetime import datetime
from django.conf import settings
class LogTime(object):

        def __init__(self):

                self.log = logging.getLogger("tm")
                self.log.setLevel(logging.INFO)
                formatter = logging.Formatter('[%(asctime)s] "%(message)s"','%Y-%m-%d %a %H:%M:%S')
                if len(self.log.handlers) == 0:
                        hdlr = logging.FileHandler(settings.LOG_TIME_FILE)
                        hdlr.setFormatter(formatter)
                        self.log.addHandler(hdlr)

        def process_request(self,request):

                request.dtLogTimeStart = datetime.now()

        def process_response(self,request,response):
                if 'dtLogTimeStart' in dir(request):
                        delta = datetime.now()-request.dtLogTimeStart
                        self.log.info("req: %s - time: %i.%06i" % (request.path,delta.seconds,delta.microseconds))
                return response

[Tip] Python: imprimir el traceback

Cuando programamos es habitual encontrarnos con errores que son difíciles de depurar si no tenemos información sobre lo que ha pasado.

En Python, lo normal es que de forma automática aparezca el traceback cuando se produce una excepción:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'ls' is not defined

Hay ocasiones en los que obtener esta información no es tan trivial.
Un ejemplo común es el desarrollo de servicios webs. En este caso no sirve de nada imprimir por pantalla el error, ya que no queda registrado en ningún sitio.

Para poder obtener el traceback y depurar correctamente el servicio, podemos hacer uso del módulo traceback.

El siguiente codesnippet permite imprimir en el archivo de log el correspondiente traceback:


try:

# Código bajo sospecha

....
except:

import traceback
import StringIO
s=StringIO.StringIO()
traceback.print_exc(file=s)
s.seek(0)
msg=s.read()
logging.debug("TRACEBACK: %s" % msg)

[Tip] Convierte imágenes en formato dataurl con Python

Como muchos sabréis es posible introducir imágenes en la propia página web.

¿Cómo? Mediante la sintaxis dataURL.

Normalmente, en nuestra página tendriamos algo como:


<img src="ruta/imagen.jpg">

Con la sintaxis para contenidos embebidos tendría la siguiente forma:


<img src="data:image/jpeg;base64,RABAAAB...cadena algo grande..ABA//">

Lo ideal sería usar el mecanismo de siempre, pero para ciertas aplicaciones lo mismo interesa incrustar las imágenes (carga de imágenes de una base de datos local).

He escrito un pequeño script en Python que convierte una imagen dada a dicho formato. Que lo disfruteis 🙂


#!/usr/bin/env python
import base64import sysimport Image
if __name__ == "__main__":
if len(sys.argv) < 2:
print sys.argv[0],"<imagefile>"
sys.exit(0)

try:
im = Image.open(sys.argv[1])

except:
print "cannot open image file",sys.argv[1]
sys.exit(-1)

f =  im.format.lower()
data = open(sys.argv[1],"rb").read()
print "data:image/%s;base64,%s" % (f,base64.b64encode(data))

 

 

 

Ejecuta scripts mediante Email en Python

Majordomo en python

Majordomo en python

Hoy os traigo una utilidad recién sacada del horno. Se trata de una implementación sencilla y simplificada de los famosos Majordomos. Para el que no lo sepa un majodormo es un programa en background que monitoriza una cuenta de email asociada y ejecuta comandos/scripts si encuentra ciertas palabras claves. Si alguna vez te has suscrito a alguna lista de distribución, es muy probable que lo hayas usado indirectamente.

Los casos de uso de un majordomo son muy amplios. En el campo de los administradores de equipos es de bastante utilidad, ya que se realizan tareas de mantenimiento en equipos que suelen ser remotos. La idea es que enviando una palabra mágica a una dirección de correo determinada, el majordomo empiece a trabajar, y que cuando termine nos mande un email para avisarnos.

La implementación la he hecho en Python y uso cron para ejecutar el script cada 5 minutos en busca de nuevos correos (órdenes).

Los scripts son: majoProcess.py y  sendNotify.py

majoProcess.py


#!/usr/bin/env python
import poplib
import string
import os
from random import random

USER="<usuario>"
PASS="<contraseña>"
SERVER_POP3="<servidor-smtp>"
MAGIC_WORD="<secreto>"
TO="uncorreo@undominio.com"
SUBJECT_OK='"Proceso listo'
SUBJECT_FAIL='"Error al ejecutar el proceso"

SUBJECT_INIT='"Proceso en background iniciado"'

if __name__ == "__main__":

 magicFound = False
 M = poplib.POP3(SERVER_POP3)
 M.user(USER)
 M.pass_(PASS)
 n = len(M.list()[1])
 for i in range(n):
 for j in M.retr(i+1)[1]:
 if string.find(j,MAGIC_WORD) != -1:
 magicFound = True
 break;
 # Borramos mensajes
 for i in range(n):
 M.dele(i+1)
 M.quit()
 if magicFound:
 print "Magic word found"
 # Ejecutar proceso
 os.system("/usr/local/bin/sendNotify.py %s %s %s" % (TO,SUBJECT_INIT,'"iniciando proceso"'))
 ret = os.system("<comando/script>")
 if ret == 0:
 os.system("/usr/local/bin/sendNotify.py %s %s %s" % (TO,SUBJECT_OK,'"proceso terminado correctamente"'))
 else:
 os.system("/usr/local/bin/sendNotify.py %s %s %s" % (TO,SUBJECT_FAIL,'"proceso acabado"'))

sendNotify.py


#!/usr/bin/env python

import sys
import datetime
from smtplib import SMTP

FROM="Majordomo <majodomo@dominio.com>"
USER="<user>"
PASS="<password>"

SERVER_SMTP="<server-smtp>"
PORT_SMTP=<smtp-port>

HEADER="Mensaje automatico generado: "

if __name__ == "__main__":

 if len(sys.argv) < 4:
 print "syntax: %s <email-dest> <subject> <msg>" % sys.argv[0]
 sys.exit(0)

 smtp = SMTP()
 smtp.connect(SERVER_SMTP,PORT_SMTP)
 smtp.login(USER,PASS)
 to = sys.argv[1]
 subject = sys.argv[2]
 message = sys.argv[3]
 date = datetime.datetime.now().strftime("%d/%m/%Y %H:%M")
 msg = "From: %s\nTo: %s\nSubject: %s\nDate: %s\n\n%s %s\n%s" % (FROM,to,subject,date,HEADER,date,message)
 smtp.sendmail(FROM,to,msg)
 smtp.quit()

Basta configurar cron añadiendo la siguiente línea que ejecuta nuestro script cada 5 minutos (*/60):


*/5 * * * * root /usr/local/bin/majoProcess.py

Bueno, espero que a alguno le sirva este sencillo majordomo (ojalá los majordomos supieran hacer cafe 🙂 )

Translate to:English
MenefanteMenéame TwitterTwitter

Benchmark a GoLang: servidor web en Go vs Python

Translate to:English

Benchmark GoLang vs Python

Benchmark GoLang vs Python

Manos a la obra. Una de las principales motivaciones de GoLang (el lenguaje de programación Google) es obtener en un sólo lenguaje la flexibilidad y rápido desarrollo que proporciona Python pero con la velocidad que un código nativo como C proporciona.

Quiero comprobar esto con un ejercicio inmediato y práctico: hacer un benchmark comparando un servidor web en python contra otro en GoLang.

Las herramientas que he usado son:

  • Servidor web simple en Python (Python 2.5.2) [Fuente]
  • Servidor web simple en GoLang (GoLang hg 10/11/2009 snapshot) [Fuente]
  • Apache HTTP server benchmarking tool (ab v2.3)

La máquina donde he ejecutado los tests es:

  • Intel Core 2 Extreme X9770 3.2 Ghz
  • Ubuntu 8.10 Intrepid amd64
  • Kernel 2.6.27-15-generic

Vamos allá.

Leer más de esta entrada