October 2017 - Arkhotech

Agregando valor de Negocio – desde Trello hacia Domo

Desde hace ya bastante tiempo, y en nuestra estrategia de agilidad, hemos probado diferentes herramientas para mantener visibilidad de nuestro trabajo día a día. Sin hablar mucho de las otras herramientas, considero Trello nos ha traído grandes beneficios por su simpleza y facilidad de uso; no hay que explicar mucho a alguien que nunca lo ha visto o no tiene mucha experiencia, y eso, es más que valioso.

En mi perspectiva, si hay algo que no tienes en tu lista de pendientes, entonces no existe; y esto es lo que para mi gusto, Trello resuelve muy bien, todo lo que se te ocurra es muy sencillo de apilar… Ahora bien, si solo sumas a tu bandeja de entrada tareas y tareas que nunca se mueven, ese es otro problema; recuerden movimiento es muy diferente a progreso.

La manera versátil de organizar tareas en listas que propone trello hace mucho sentido en los tableros que queremos potenciar, tanto personales como grupales, pero en estos últimos es donde más encontramos valor, y los usamos para todo! … Aquí algunos ejemplos:

  • Metas semanales → Mensuales → Anuales. ¿Scrum de scrums? Esta es la fuente, también hay una pizarra física, pero cuando hay gente remota lo físico pierde valor.
  • Clientes (Mini-CRM). Cuántos clientes están activos? Cuántos han dejado de tener movimiento? Prospectos? Perdidos? Bueno, acá están todos…
  • Vacaciones:  Sí, hasta las peticiones de fechas se hacen por Trello! Chao correos o herramientas de RRHH que nadie entiende. Cuatro columnas son suficientes: Solicitadas, Aprobadas, Actuales y Tomadas. Además, se calculan automáticamente los días que te debe la compañía.
  • Colaboradores: Personas, Alianzas, Partners, Asociados y hasta la gente que se ha ido en un solo lugar… Algun teléfono? bueno ahi está su VCF, Foto, Ficha y hasta su foto por si no tenemos ni idea quién es.
  • Proyectos: actuales, exitosos, fracasos, servicios. Una cuenta total? Fácil, mediante la API de Trello. Fuente genial para estadísticas de compañía.
  • Asignaciones (staffing): Quién está en qué y con qué asignación. Muy útil, pero hay que actualizarla! OjO.
  • Ventas (Revenue)Tres columnas hacen magia: Facturas pendientes (proyección), emitidas y pagadas. Cada una con su monto, en un formato estándar. Tip, usar story points para el monto funciona perfecto.
  • Tareas Administrativas y Caja Chica. Bastante más claro que un excel en muchas oportunidades. Además, la secretaria siempre tendrá una visibilidad tremenda, lo que hace y deja de hacer.
  • Operaciones. Bueno, por último para algunos proyectos, donde la gestión es suficiente  con un simple Kanban… pero para proyectos que requieren muchas más métricas no es muy recomendable. Ejm, Tiempos consumidos (work-log).

Todo esto suena bien. Sin embargo, hizo falta algo, ¿cómo interpretar la gran cantidad de datos que se suben a los tableros día a día? Bueno para ello, primero hicimos varias cosas:

  1. Lo que está en la parte de más arriba es lo que tiene más prioridad.
  2. Las tareas deben tener etiquetas que permitan clasificar más adelante. Ojalá esta clasificación sea muy acotada, no vale la pena tener 100 etiquetas diferentes.
  3. Idealmente una persona por tarjeta. Responsabilidad compartida, no es de nadie.
  4. Agregar fechas de venciento es tan importante como agregar la tarea, da un marco de acción.
  5. Integrar Trello con alguna herramienta de chat, en nuestro caso Slack. La notificación del movimiento de una tarea es muy importante para la inercia de equipo. Muchos no lo perciben o le prestan atención, pero que haya uno entre diez, es suficiente.
  6. Finalizado (Done) es finalizado, no es casi finalizado, o falta poco, o de seguro mañana se cierra y me adelanto a cerrarlo. La definición de Finalizado, es una discusión muy importante, el consenso de equipo es lo que la hace poderoso.
  7. Limpiar los boards de manera recurrente, lo que está en Terminado pasa a ser archivado cada semana.
  8. Un reporte diario 8am (vía Mail), para empezar el día y ver donde estoy como deudor. Aquí es donde empieza a aparecer nuestra nueva herramienta.

Con todo esto, de nuevo parece que falta algo… la información es poco visible cuando el equipo crece y las tareas abundan; para esto, buscamos alguna herramienta que permita generar estadísticas y métricas de acuerdo a nuestros tableros, y … nuestra elección fue DOMO, una herramienta BI que permite interpretar datos de múltiples fuentes, procesarlos y desplegarlos en múltiples formatos, para ayudar a la toma de decisiones de negocio. Es bastante potente, se pueden combinar múltiples fuentes de datos, esta alojada en la nube y la modalidad gratis es suficiente para lo que buscamos.

Que hacemos con Domo entonces? Primero, conectamos Trello como fuente de datos, el permiso es por 30 días, así que cada mes toca renovar las credenciales para no perder acceso. El usuario que hace la integración, debe pertenecer a todos los tableros que se quieran leer, para ello usamos un usuario genérico para evitar depender de alguien en particular. Una vez con la integración lista, programamos una tarea en modalidad segundo plano todos los días a las 7am para traer lo último de las tarjetas y tenerlas como fuente de datos de Domo.

Una vez la data esta disponible, se crean páginas que agrupan tarjetas (no de trello), que corresponden básicamente a un gráfico o métrica. Aquí algunos ejemplos de lo que se puede lograr.

 

Esta es una muestra de lo que ha sido valioso para el equipo, algunas se han ofuscado por obvias razones; acá se muestran como modelo de inspiración o crítica, lo importante es que las métricas elegidas sean útiles a toda la organización.

Cada tarjeta tiene su detalle, por ejemplo, cuando se da click sobre una particular, se muestra el detalle asociado. Ejemplo, para clientes:

Bien, todos estas tarjetas (gráficos) se generan mediante una especie de tabla dinámica de excel, en un modo llamado “Analyzer”, donde se establecen las dimensiones de información y se puede jugar con datos calculados y formulas dinámicas (Beast mode) que la herramienta provee. Los tipos de gráfico disponibles son bastante completos y ricos visualmente, desde “funnel” de conversión, tablas,  “data science”, mapas y muchos más. Aún queda mucho por explorar, pero algo bien interesante es que las tarjetas ahora pueden ser embebidas dentro de contenido html en cualquier lugar o publicarse en redes sociales como Twitter, Facebook y LinkedIn.

¿Qué es lo más complicado? Bien, la exportación de Trello aún tiene muchos detalles por mejorar, y uno de las más complicadas es que las listas no son exportadas con el nombre, sino con el identificador único, por tanto, hay que hacer un mapeo/traducción para saber a que columna pertenece; lo bueno de esto, es que se hace una vez y de ahi se comparte a todas las tarjetas (como campo calculado). Un ejemplo de ello, es una función no tan limpia como:

CASE when `idList` = '58c36bb5f7781a57df6dba6c' then 'Inbox'
when `idList` = '56bf30f9e7857bb868a04b25' then 'Inbox'
when `idList` = '577d0f282076b7a67c595355' then 'Inbox'
when `idList` = '58c43cbc823286e6fa47d13e' then 'In Progress'
when `idList` = '5952afda7d036e870a9c33f8' then 'In Progress'
when `idList` = '596e4ef1ea1b31b1fbf6d1f7' then 'In Progress'
when `idList` = '58c43cbe3774edac9afe567a' then 'DONE'
when `idList` = '58e79a3918388b9ff9ef5516' then 'DONE'
else 'Other' End

Algo también que puede ser complicado, es que cuando una tarjeta en trello pertenece a dos personas, la exportación la toma como dos registros independientes y no un solo registro.

¿Qué queda faltando? Algo que se extraña de manera simple, es el poder comparar el día anterior con el actual, en ocasiones es útil poder determinar tendencias y contar con algo que permita validar si hubo un cambio o no con relación a la instancia inmediatamente anterior. De seguro se puede realizar, pero la implementación a primera vista no sería tan sencilla. En todo caso, Domo es una herramienta bastante versátil y va más allá del uso que le estamos dando acá.

Finalmente, siempre considerar que el valor más importante no está en las herramientas, sino en lo que podemos crear explorando y explotando las funcionalidades que nos brindan las elecciones tecnológicas que hacemos. Sin duda, tanto Trello como Domo, tienen muchos más usos de los acá planteados, pero la invitación es a probarlos, ajustarlos a las necesidades particulares y compartir los resultados.

ELK Stack

El stack ELK es una solución para la recolección, la centralización y la explotación de logs.
Estos últimos años, se ha vuelto la solución recomendada para los sistemas complejos y distribuidos que generan muchos logs.

Lleva al menos esos tres componentes:
E para ElasticSearch
L para Logstash
K para Kibana

ElasticSearch

Es una base de datos orientada a documentos (JSON) con schema opcional, tiene tres casos de uso principales :

  • Motor de búsqueda de texto
  • Análisis de logs
  • Business Intelligence

ElasticSearch es muy bueno para almacenar grandes volúmenes de documentos, indexarlos, y buscar textos en ellos, lo que le hace una herramienta muy adaptada para analizar las cantidades de archivos logs que generan las aplicaciones hoy en día.

Logstash

Es un procesador de datos, que funciona como un pipeline en tres partes :

  • Input
  • Filter
  • Output

Logstash viene con varios plugins de entrada y salida, lo que le permite colectar datos de varios fuentes y mandarlos a varias partes, los plugins de filtro, permiten tratar estos datos dándole sentido, como por ejemplo, convirtiendo una IP en una zona geográfica.

Kibana

Es un visualizador de datos, especialmente desarrollado para ElasticSearch.
Permite explorar los datos recolectados en ElasticSearch, construir varios tipos de gráficos, incluyendo mapas, y componer dashboards a partir de esos gráficos.

Elastic

Esos tres componentes son obras de la compañía Elastic (https://www.elastic.co/) y son Open Source :
– ElasticSearch (Java) https://github.com/elastic/elasticsearch
– Kibana (Javascript) https://github.com/elastic/kibana
– Logstash (Ruby) https://github.com/elastic/logstash

¿Como funcionan juntos?

La configuración de ElasticSearch y Kibana es bastante fácil, solo hay que indicarle a Kibana la URL de ElasticSearch, por ejemplo en una configuración docker-compose :

elastic:
image: docker.elastic.co/elasticsearch/elasticsearch:5.6.3
volumes:
- logs:/usr/share/elasticsearch/data
ports:
- 9200:9200
kibana:
image: docker.elastic.co/kibana/kibana:5.6.3
environment:
- ELASTICSEARCH_URL=http://elastic:9200
ports:
- 5601:5601
depends_on:
- elastic

Eso aplica también para el output de Logstash, solo hay que ocupar el plugin de salida para ElasticSearch y indicarle la URL:

output {
    elasticsearch {
        hosts => "elastic:9200"
    }
}

Lo más complicado es la recolección de los logs, ya que no hay dos aplicaciones que ocupen el mismo formato.

Modelo 1
Logstash puede colectar los logs directamente desde el filesystem, pero en este caso, se necesitará una instancia de logstash en cada nodo. Es el modelo 1, que se representa a continuación :

ELK1

Modelo 2
Un modelo más evolucionado consiste en ocupar Filebeat, es un agente liviano especialmente escrito para ese caso de uso, es capaz de comunicarse con Logstash de forma inteligente. También es de Elastic y es Open Source (escrito en Go), hace parte de una familia más grande llamada “Beats” que conlleva otros productos relacionados.
En este modelo, se puede tener una instancia única de Logstash con un agente Filebeat en cada nodo :

ELK2

Modelo 3
Finalmente, se pueden configurar los componentes en un tercer modelo, agregándole un message queue broker, lo que permite desacoplar la recolección y el tratamiento de los logs :

ELK3

De esa forma, se puede detener el ElasticSearch, por mantención por ejemplo, sin pérdida de logs, ya que se acumulan en la cola. También permite que no se colapse el sistema cuando llegan muchos logs al mismo tiempo; la cola hará un papel de amortiguador de carga, en ese caso. Como Message Broker, entre otros, se puede ocupar Redis.
Existen plugins de entrada y de salida para Logstash.

Salida:

output {
    redis {
        host => "redis"
        data_type => "list"
        key => "logstash"
    }
}

Entrada:

input {
    redis {
        host => "redis"
        data_type => "list"
        key => "logstash"
    }
}

Ejemplos de configuración de Filebeat

Este ejemplo es una configuración (filebeat.yml) que mueve los logs de un servidor HTTP Nginx a una instancia Logstash:

filebeat.prospectors:
- input_type: log
paths:
- /var/log/nginx/access.log
name: "nginx"
output.logstash:
hosts: ["logstash-collector:5044"]

Este segundo ejemplo colecta los logs de una aplicación corriendo en JBoss:

filebeat.prospectors:
- input_type: log
paths:
- /opt/jboss/jboss-eap-6.4/standalone/log/server.log
multiline:
pattern: '^[0-9]{2}/[0-9]{2}/[0-9]{4}'
negate: true
match: after
- input_type: log
paths:
- /opt/jboss/jboss-eap-6.4/standalone/log/app/*.log
multiline:
pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
negate: true
match: after
name: "hub"
output.logstash:
hosts: ["logstash-collector:5044"]

Acá se puede ver que Filebeat es capaz de leer desde diferentes archivos, y también, gracias al multiline pattern, de unir varias líneas del archivo en una sola entrada de log (lo que típicamente ocurre con los logs que producen las aplicaciones Java).

Ejemplos de configuración de Logstash

Este es un ejemplo de archivo de configuración en el modelo 3.
Corresponde a la primera instancia de Logstash que colecta los logs de los diferentes agentes Filebeat y los manda en Redis, sin tratamiento inmediato.

Archivo logstash.conf :

input {
    beats {
        port => 5044
    }
}

output {
    redis {
        host => "redis"
        data_type => "list"
        key => "logstash"
    }
}

Este segundo ejemplo, corresponde a la segunda instancia de Logstash, la que recupera los logs desde la cola Redis, los transforma en algo con sentido y los indexa en ElasticSearch :

input {
    redis {
        host => "redis"
        data_type => "list"
        key => "logstash"
    }
}

filter {
    if [beat][name] == "meta" {
        if [source] = ~"meta-search\.log$" {
            grok {
                match => {
                    "message" => "(\e?\[\d+m)+\[%{DATESTAMP:datetime}\] \[%{DATA:user}\] \[%{LOGLEVEL:level}] \[th:%{DATA:thread}\] \[%{GREEDYDATA:category}\]:%{INT:line} - %{GREEDYDATA:message}"
                }
                overwrite => ["message"]
            }
        } else {
            grok {
                match => {
                    "message" => "\[%{DATESTAMP:datetime}\] \[%{DATA:user}\] \[%{LOGLEVEL:level}] \[%{GREEDYDATA:category}\]:%{INT:line} - %{GREEDYDATA:message}"
                }
                overwrite => ["message"]
            }
        }
        date {
            match => ["datetime", "dd/MM/yyyy HH:mm:ss,SSS"]
            timezone => "America/Santiago"
            remove_field => ["datetime"]
        }
    } else if [beat][name] == "hub" {
        if [source] = ~"server\.log$" {
            grok {
                match => {
                    "message" => "%{DATESTAMP:datetime} %{LOGLEVEL:level} +\[%{GREEDYDATA:category}\] \(%{DATA:thread}\) %{GREEDYDATA:message}"
                }
                overwrite => ["message"]
            }
            date {
                match => ["datetime", "dd/MM/yyyy HH:mm:ss,SSS"]
                timezone => "America/Santiago"
                remove_field => ["datetime"]
            }
        } else {
            grok {
                match => {
                    "message" => "%{TIMESTAMP_ISO8601:datetime} %{LOGLEVEL:level} %{GREEDYDATA:category}:%{INT:line} - %{GREEDYDATA:message}"
                }
                overwrite => ["message"]
            }
            date {
                match => ["datetime", "yyyy-MM-dd HH:mm:ss"]
                timezone => "America/Santiago"
                remove_field => ["datetime"]
            }
        }
    } else if [beat][name] == "hazelcast" {
        grok {
            match => {
                "message" => "%{MONTH:month} %{MONTHDAY:day}, %{YEAR:year} %{TIME:time} (?<ampm>[AP]M) %{GREEDYDATA:category}\n%{LOGLEVEL:level}: \[%{GREEDYDATA:ip}\]:?(?<port>[0-9]{0,5}) \[%{GREEDYDATA:groupname}\] \[%{GREEDYDATA:version}\] ?%{GREEDYDATA:message}"
            }
            overwrite => ["message"]
        }
        mutate {
            add_field => {
                "datetime" => "%{year} %{month} %{day} %{time} %{ampm}"
            }
        }
        date {
            match => ["datetime", "yyyy MMM dd h:mm:ss a"]
            timezone => "America/Santiago"
            remove_field => ["year", "month", "day", "time", "ampm", "datetime"]
        }
    } else if [beat][name] == "elasticsearch" {
        grok {
            match => {
                "message" => "\[%{TIMESTAMP_ISO8601:datetime}\]\[%{LOGLEVEL:level} ?\]\[%{NOTSPACE:category} *\] \[%{WORD:nodename}\] %{GREEDYDATA:message}"
            }
            overwrite => ["message"]
        }
        date {
            match => ["datetime", "ISO8601"]
            timezone => "America/Santiago"
            remove_field => ["datetime"]
        }
    } else if [beat][name] == "nginx" {
        grok {
            match => {
                "message" => "\[%{HTTPDATE:time_local}\]\[%{IPORHOST:remote_addr}\]\[%{GREEDYDATA:request}\]\[%{INT:status}\]\[%{INT:body_bytes_sent}\]\[%{GREEDYDATA:http_user_agent}\]"
            }
        }
        date {
            match => ["time_local", "dd/MMM/YYYY:HH:mm:ss Z"]
            remove_field => ["time_local"]
        }
        geoip {
            source => "remote_addr"
        }
        useragent {
            source => "http_user_agent"
        }
    }
}

output {
    elasticsearch {
        hosts => "elastic:9200"
    }
}

Por supuesto, es acá donde ocurre toda la magia, por ejemplo el filtro geoip permite sacar informaciones geográficas de las IP que aparecen en los logs de Nginx, el filtro useragent sirve para formatear el http header user-agent en el tipo de navegador que ocupan los clientes.

El filtro grok, sin duda el más importante, permite separar los diferentes campos que lleva cada mensaje del log, gracias a expresiones regulares, que ocupan un formato bien particular.

Resultó muy útil ocupar este tester online: http://grokconstructor.appspot.com/do/match, que permite probar la sintaxis del pattern grok con extractos de su archivo log. Kibana en sus últimas versiones, también incluye un debugger de grok patterns.

El filtro date también es muy importante ya que permite asignar a cada entrada del log la fecha real en la cual sucedió el evento, sin eso, por defecto se le asignaría la fecha de entrada en Logstash que no es necesariamente pertinente.

En un próximo post, introduciremos el stack EFK, que es más adecuada para recolectar y centralizar los logs en un entorno basado en contenedores Docker.