martes, 24 de marzo de 2015

Logs Queries de MongoDB con Mongotail

Mongotail es una herramienta de línea de comandos que permite ver los logs de las últimas queries (o todas) ejecutadas en una base de datos Mongo, de una manera similar a la que el comando "tail" nos permite ver las últimas líneas de un archivo. Esto es realmente útil cuando estamos teniendo problemas de performance y necesitamos saber dónde se están consumiendo los recursos, o porqué una aplicación que suponemos hace una consulta no nos devuelve el resultado que esperamos, entre otros casos de uso.

Desarrollé la herramienta con Python hace poco más de un mes, y hace unos días publiqué en los repositorios PyPI una última versión con mejoras, por lo que no es necesario saber nada de Python ni de como instalar un script en el PATH del sistema, ya que podemos instalarlo como un comando más del sistema con una herramienta llamada PIP (describiré los pasos luego).

Ejecutando mongotail NOMBRE_BBDD nos dará las últimas 10 instrucciones ejecutadas en la base de datos, pero lo más interesante es usarlo con la opción -f, que nos permite dejar el comando en modo "escucha" a que nuevas consultas sean ejecutadas en la base, las cuales serán mostradas en la consola a medida que se ejecutan. También al igual que se suele hacer con tail, podemos redireccionar la salida a un archivo log, o filtrar la salida con | (pipe) hacia algún comando que tome ésta como entrada, el caso más común es hacerlo con el comando grep para filtrar el resultado.

Pero vamos por paso, MongoDB tiene un módulo llamado Database Profiler que permite guardar información de qué queries se están ejecutando en una BBDD, y la almacena en una collection especial llamada system.profile dentro de la misma base, pero este feature por default es desactivado en todas las bases en el arranque de MongoDB, ya que ralentiza levemente la performance de las BBDDs, y también puede ser un problema de seguridad si es una base de producción a la cual no tenemos un buen control de quién accede a la misma. Por el espacio que ocupará este registro no nos debemos hacer problema, ya que es una capped collection: algo así como una tabla con estructura de cola, donde hay un tope máximo, y cuando llegamos a ese tope, los registros más antiguos son automáticamente borrados.

Usando la herramienta

Vamos a suponer que tenemos una BBDD en una instancia local de MongoDB que se llama "ventas". Para activar el logging de la BBDD ejecutamos desde la consola:

$ mongotail ventas -l 2
Profiling level set to level 2

A partir de este momento todas las queries ejecutadas serán registradas. Para mostrarlas, simplemente volvemos a ejecutar el comando anterior sin opciones, o con la opción -n NUMERO_LINEAS, que nos permite especificar cuantos comandos del historial mostrar (siempre los últimos ejecutados), o -n all, que mostrará el registro completo.

Por ejemplo, supongamos que tenemos una collection llamada "zips", y queremos listar todos los registros donde el campo "state" sea "CA" por línea de comandos con el comando mongo, o con algún otro cliente como Robomongo:

$ mongo ventas

ventas> db.zips.find({"state": "CA"})
{"_id": "90016", "city": "LOS ANGELES","loc": [-118.352787,34.029826], "pop": 43669, "state": "CA"}
{"_id": "90017", "city": "LOS ANGELES", "loc": [-118.266582, ...

Si luego desde la consola ejecutamos:

$ mongotail test
2015-03-17 12:34:12.552 QUERY  [zips] : {"state": "CA"}

Mongotail nos da información de cuándo, qué tipo de operación (QUERY, COUNT, INSERT, UPDATE, REMOVE, MAP...), qué documento y con qué parámetros fue consultada la base.

Pero como había mencionado antes, lo más interesante es usarlo con la opción -f, y ver los cambios en "tiempo real", mientras por ejemplo ejecutamos una aplicación que accede a la base. Además, como mongotail imprime el resultado en la "salida estándar", podemos redireccionarlo a un archivo de registro, o filtrar qué consultas deseamos ver con grep/egrep.

En el siguiente ejemplo, ejecutamos mongotail con la opción -f para ver las queries a medida que suceden, y además redireccionaremos la salida al comando grep para que nos filtre solo las queries que modifican la información de la base, omitiendo consulta de datos:

$ mongotail ventas -f | egrep "(INSERT|UPDATE|REMOVE)"

Al finalizar la "inspección" de queries, debemos recordar desactivar el logging por las razones ya mencionadas:

$ mongotail ventas -l 0
Profiling level set to level 0

Para ver más opciones de ejecución, ver la lista completa con:

$ mongotail --help

Instalación

La instalación en una distribución Linux es bastante sencilla, primero debemos asegurarnos de tener el comando pip instalado. Para verificarlo, simplemente ejecutamos el comando sin parámetros desde la consola:

$ pip

Si obtenemos una página de ayuda de resultado, tenemos el comando!, si en cambio obtenemos un error similar a command not found: pip, significa que tenemos que instalarlo.

En distribuciones Debian/Ubuntu,podemos hacerlo con:

$ apt-get install python-pip python-dev

Tener en cuenta que en Debian hace falta estar autenticado como usuario root, en cambio en Ubuntu podemos hacerlo directamente con cualquier usuario, pero anteponiendo al comando anterior la instrucción sudo para que nos de privilegios de administrador en la ejecución.

Finalmente, para instalar mongotail con pip, ejecutamos (también con privilegios de administrador):

$ pip install mongotail

Acerca del proyecto

Mongotil todavía está en desarrollo, es open source y pueden descargar el código fuente desde Github. Es posible que tenga algunos fallos, y que le agregue algunos features adicionales en el futuro, si tienen algún inconveniente usándolo, no duden en reportar el error en https://github.com/mrsarm/mongotail/issues.

También, pueden hacer click en el ícono "Star" con su cuenta de Github si les es útil el proyecto.