DEV Community

Jorge
Jorge

Posted on • Originally published at jorge.aguilera.soy on

Enviar alertas de Kibana a Telegram

Lo que no se define no se puede medir. Lo que no se mide, no se puede mejorar. Lo que no se mejora, se degrada siempre

— William Thomson Kelvin

| | Este post no es continuación de logs-metricas.html pero están muy relacionados. De hecho sin el primerono se me habría ocurrido este otro, sin embargo como ya he dicho son independientes. |

Kibana (ELK)

Kibana es una interfaz de usuario gratuita y abierta que te permite visualizar los datos de Elasticsearch y navegaren el Elastic Stack. Realiza lo que desees, desde rastrear la carga de búsqueda hasta comprenderla forma en que las solicitudes fluyen por tus apps (https://www.elastic.co/es/kibana)

Kibana es el interface que usamos para visualizar los datos (como por ejemplo logs) que Elasticsearch ingesta dediferentes fuentes.

Un uso típico puede ser el ver de forma centralizada todos los logs que va generando un stack de servicios de talforma que podamos dar un contexto único a los mismos, realizar búsquedas complejas e incluso diseñar diagramasexplotando dichos datos. Así en el post logs-metricas.html contaba cómo hacer unaanotación para servicios Grails tal que añadieran información en el contexto del log sobre la duración del métodojunto con los parámetros recibidos en el mismo. Esta meta-información puede llegar al Kibana de tal forma que no sólopuedas realizar búsquedas en el texto sino en esta meta-información.

Visualmente, esto sería un ejemplo de una línea de log en la consola web de Kibana junto con su meta-información:

t @containerId  rm26xpdn3qyx4i0ugphtplq8o/43b08f1b4da4
t @id   35625187335574879357932181753924573842110613149578166277
t @log_group    docker-logs
t @log_stream   service_1.2.rm26xpdn3qyx4i0ugphtplq8o/43b08f1b4da4
t @message  {"timestamp":"2020-08-15T10:50:49.748+0000","level":"INFO","thread":"http-apr-8080-exec-4","logger":"{...}"}
t @owner    602122916959
t @payload.className    com.puravida.service.HelloController
# @payload.duration 1,680
t @payload.methodName   hello
t @replica  2
t @service  service_1
 @timestamp Aug 15, 2020 @ 10:50:49.748
t _id   35625187335574879357932181753924573842110613149578166277
t _index    cwl-2020.08.15
# _score -
t _type docker-logs-production
t context   default
t correlationId 8f9b465a-d08c-4d95-b65b-82398d3dc127
t level INFO
t logger    com.puravida.service.HelloController
t message   com.puravida.service.HelloController.hello: duration=1680 ms;
t thread    http-apr-8080-exec-4
 timestamp  Aug 15, 2020 @ 10:50:49.748
t userId - not logged -
Enter fullscreen mode Exit fullscreen mode

Como puedes ver en este registro de Elasticsearch no sólo tenemos el message generado sino una serie de meta-camposextras como el @payload generado por nuestra anotación.

Gracias al motor de búsqueda de Elasticsearch desde Kibana puedes filtrar logs que contengan un valor de interés enestos metacampos, por ejemplo puedes filtrar:

@payload.className:HelloController

y obtener todos los logs generados por este controller y extraer de ellos el campo @payload.duration

Realizar gráficas que usen este campo junto, en un intervalo de tiempo definido en @timestamp es cuestión de minutos.

Telegram

A día de hoy asumo que prácticamente todo el mundo conoce Telegram (si estás leyendo este post probablemente es porqueincluso eres usuario de este sistema de mensajería).

Una de las características de Telegram sobre otros sistemas es la posibilidad de crear canales y bots de forma simple(y gratuita) incluso privados.

| | En https://core.telegram.org/bots#6-botfather tienes la documentación oficial sobre cómo crear bots |

En primer lugar (y siendo usuarios de esta plataforma) crearemos un bot mediante el BotFather (el bot de Telegramque nos sirve para crear y gestionar nuestros bots):

  • buscar desde la aplicación "botfather" y comenzar un diálogo con él

  • crear un bot siguiendo los pasos (dar un nombre y un id terminado en "bot" básicamente)

  • obtener el token. No hace falta guardarlo en lugar seguro pues podremos consultarlo en cualquier momento, pero nolo compartas más que con gente de confianza y ojo no guardarlo en un repositorio git público.

En segundo lugar crearemos un canal privado, por ejemplo "Puravida Alerts" y añadir al bot como administrador del canal. Puedes restringir sus permisos para que solamente pueda publicar mensajes. Así mismo hay que añadir a otros usuariosque puedan estar interesados en las alarmas.

Como el canal será privado (a no ser que quieras que cualquiera pueda suscribirse y ver las alertas) necesitaremosconocer su ID, que a diferencia del público donde es el @nombre_del_canal. Para ello tendremos que usar el interfaceweb de Telegram (desconozco si se puede con el móvil, yo no lo he conseguido). Simplemente navegaremos hasta el canalcreado con el navegador y nos fijaremos en la url que tiene asignada el canal:

https://web.telegram.org/#/im?p=cXXXXXXX_yyyyyyyyy

El id del canal será "XXXXXXX", es decir el número comprendido entre c y _ en la URL

Alertas

El stack ELK (Kibana+Elasticsearch) cuenta con un ecosistema de plugins bastante extenso del cual vamos a usar paralas alarmas el de opendistro (https://opendistro.github.io/for-elasticsearch/)

Si quieres probarlo primero antes de instalarlo en tu stack, puedes usar este docker-compose como punto de partida:

(1)
version: '3'
services:
  odfe-node1:
    image: amazon/opendistro-for-elasticsearch:1.9.0
    container_name: odfe-node1
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node1
      - discovery.seed_hosts=odfe-node1,odfe-node2
      - cluster.initial_master_nodes=odfe-node1,odfe-node2
      - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems
        hard: 65536
    volumes:
      - odfe-data1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9600:9600 # required for Performance Analyzer
    networks:
      - odfe-net
  odfe-node2:
    image: amazon/opendistro-for-elasticsearch:1.9.0
    container_name: odfe-node2
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node2
      - discovery.seed_hosts=odfe-node1,odfe-node2
      - cluster.initial_master_nodes=odfe-node1,odfe-node2
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - odfe-data2:/usr/share/elasticsearch/data
    networks:
      - odfe-net
  kibana:
    image: amazon/opendistro-for-elasticsearch-kibana:1.9.0
    container_name: odfe-kibana
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      ELASTICSEARCH_URL: https://odfe-node1:9200
      ELASTICSEARCH_HOSTS: https://odfe-node1:9200
    networks:
      - odfe-net

volumes:
  odfe-data1:
  odfe-data2:

networks:
  odfe-net:
Enter fullscreen mode Exit fullscreen mode

| 1 | Sí, es el mismo que viene en la web de opendistro pero así hago este post más extenso |

Básicamente levanta dos nodos de Elasticsearch y uno de Kibana con los plugins configurados. Una vez levantado puedesacceder a localhost:9200 y usar admin:admin para logearte.

La idea principal va a consistir en crear:

  • un monitor que inspeccione los registros cada cierto tiempo

  • un trigger que se ejecute dentro de este monitor cuando los registros cumplan una condicion

  • un destination a donde enviar la alarma

Destination

En primer lugar crearemos un destination (objetivo principal de este post) Puravida Telegram:

  • name: Puravida Telegram

  • type: Custom

  • custom attributes:

-- host: api.telegram.org

-- path: botELTOKENDELBOT-INCLUIDO-LOS-DOS-PUNTOS/sendMessage

  • header information: -- Content-Type: application/json

Es importante escribir bien la url:- texto fijo "bot"- el token obtenido con BotFather incluidos los dos puntos, tal que XXXXXXX:YYYYYYYYYY- terminar en /sendMessage

| | Así mismo es necesario añadir un header con el Content-Type como application/json |

Monitor

A continuación crearemos un Monitor

  • name: Slow HelloWorld

  • schedule: every 10 mnts

y usando el interface visual definiremos el monitor:

  • index: cwl-* (o el que hayas definido)

  • time field: @timestamp

crearemos una expresión para indicar el filtro a aplicar sobre los documentos:

kibana monitor

En este ejemplo le estamos indicando que seleccione la duración máxima del @payload.duration en los registrosde la última hora.

Trigger

Podemos definir tantos triggers como queramos con diferente severidad y a diferentes destinations. En nuestro casovamos a crear un trigger de severidad 1 al PuraVida Telegram destination creado anteriormente

Lo único que tenemos que hacer es darle un nombre, establecer una severidad e indicar la condición de disparo,por ejemplo:

IS ABOVE 500

lo cual enviará la alarma cuando la ejecución de HelloController sea superior a 500 mills

Añadiremos un action indicando un name a usar y seleccionando el destination PuraVida Telegram.Así mismo nos interesará personalizar el mensaje a enviar incluyendo por ejemplo la duración que ha hecho dispararla alarma por lo que cambiaremos el texto propuesto por defecto:

Message

{
"chat_id":"-100EL_ID_DEL_CHAT",
"text": "{{ctx.monitor.name}} alert\n Some HelloWorld takes {{#ctx.results}}{{#aggregations}}{{when.value}}{{/aggregations}}{{/ctx.results}} millisecs to be completed"
}
Enter fullscreen mode Exit fullscreen mode

| | Fíjate que el canal se compone de -100 y el id extraído de la URL del mismo |

Mediante el uso de {{y }} (handlebars) podremos incluir información relativa al evento. En este caso vamos aenviar el valor del aggregation: when

Para otro tipo de alarmas tienes que buscar qué información puedes extraer del contexto, básicamente inspeccionando lapropiedad hits del mismo.

Desde esta consola puedes realizar una prueba de envío usando el enlace que aparece debajo Send test message.Si todo está bien configurado recibirás una notificación en el canal indicado.

Conclusión

Si todo lo anterior ha ido correctamente a partir de ahora tendrás un job que se ejecutará según le hayas programadoy si se cumple alguna de las condiciones impuestas recibirás un mensaje en el canal.

Obviamente el destination puede ser un canal de #Slack por ejemplo, pero con los cientos de canales que tengo abiertosahí al final no les presto atención a ninguno.

TODO

Con el API de Telegram es muy fácil enviar stickers así que me anoto como tarea pendiente en lugar de enviar unmensaje de texto, definir varios niveles de criticidad y enviar un sticker diferente para cada nivel

Top comments (0)