LibBeat en PHP – Creando nuestro “log-shipper”.

En mi último proyecto me he visto en la necesidad de enviar datos desde una apliación PHP contra un elasticsearch que tenía montado. Los requisitos del proyecto eran:

  • Insertar trazas operacionales en ElasticSearch
  • Usar el protocolo Beats en un puerto específico
  • Hacerlo en PHP

Qué es ElasticSearch ?

ElasticSearch es un motor de búsqueda basado en Lucene, provee capacidad de búsqueda de texto avanzada, distribuida, y multi tenant. Proporciona fiabilidad, escalabilidad y proporciona múltiples formas de acceso a sus datos. Lucene es una base de datos no relacional (NoSql) de alto rendimineto hecha en Java y orientada a documentos, almacena los documentos en forma de JSON. Habitualmente, cuando se hace referencia a ElasticSearch se habla del stack de elasticsearch (ELK/BELK):

  • ElasticSearch: Base de datos no relacional dónde se almacena información.
  • Logstash: Procesa y prepara los documentos para insertarlos dentro de elasticsearch.
  • Kibana: Herramienta de visualización de datos.
  • Beats: Envía logs a la plataforma ELK para que sean indexados en elasticsearch.
ELK Stack
Flujo de información ELK

¿Qué es Beats?

Como ya se ha comentado en el punto anterior, Beats es el encargado de enviar información a elasticsearch. Más que una pieza de software es un concepto, todos los shippers de la familia beats tienen en común que están escritos en Go y utilizan la librería libbeat para implementar el protocolo lumberjack v2 utilizado entre logstash y los shippers beats. Existen múltiples shippers dentro de la família de beats. Los más comunes son:

  • Filebeat: Lee información de archivos de texto planos y los envía a logstash.
  • WinLogBeat: Envía logs de windows al Stack ELK.
  • PacketBeat: Captura paquetes en la red y los envía a ELK.
  • HeartBeat: Envía paquetes para saber si una máquina esta activa o no.
  • MetricBeat: Colecciona métricas de salud de las máquinas donde esta instalado y lo envía a ELK.
  • Y muchos más implementados por la comunidad

¿Cómo funciona Beats?

Tras mucho buscar no encontré nada en la red que me pudiera servir, todo el mundo terminaba usando el protocolo HTTP contra la API de Elasticsearch o contra una instancia de Logstash. Por esta razón, decidí investigar como funcionaba el protocolo de Beats. Este software implementa un protocolo conocido como Lumberjack en su segunda versión. Es un protocolo desarrollado inicialmente para logstash pero extendido y mejorado para ser más eficiente en su segunda versión.

La única información que encontré es el siguiente archivo en Github https://github.com/logstash-plugins/logstash-input-beats/blame/master/PROTOCOL.md#L12, dónde se explica vagamente el tipo de tramas que componen el protocolo pero no su uso.

Un paquete de Beats puede contener más de una trama la descripción básica de la trama es la siguiente:

### Framing

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +---------------+---------------+-------------------------------+
     |   version(1)  |   frame type  |     payload ...               |
     +---------------------------------------------------------------+
     |   payload continued...                                        |
     +---------------------------------------------------------------+

Cada trama es autocontenida y no está relacionada con la anterior. Para poder enviar una trama es necesario enviar una trama del tipo “Window” especificando el número de tramas de que se enviarán en el mismo paquete, si no se envía en el mismo paquete logstash no puede recontruir la información. Despues de la trama window se añadirán tramas de datos (Json, Gzip, Data,..), por lo que un paquete de 3 mensajes tendría la siguiente forma:

|W(3)J(Payload1)J(Payload2)J(Payload3)|

Tras este mensaje el servidor debe responder con un ack y con el último mensaje procesado:

|A(3)|

Cómo no encontré nada hecho en PHP en GitHub decidí implementar mi propia implementación de lumberjack v2. La podéis encontrar en

https://github.com/berni69/libbeat-php

O si usáis composer, podéis instalarla con:

composer require berni69/libbeat

Una vez integrada en el proyecto, es tan sencilla de usar como:

use libbeat\BeatSender;
$beat = new  BeatSender('192.168.26.12', 5044);
$beat->send("test_log");
$beat->set_compression_rate(0);
$beat->send(["test_log2", "test_log3"]);

Este sencillo código permite enviar a logstash los mensajes “test_log”, test_log2 y test_log3 mediante el protocolo beats.

El caso típico de uso es enviar las excepciones de PHP al stack de elastic para poder depurar en caso de problemas. Esto es muy útil si se crea una cola dónde se van añadiendo todas las excepciones y un proceso asíncrono va procesando la cola y la va volcando a elastic usando el código anterior para no penalizar la ejecución de PHP.


Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.