Sistema de monitoreo de datos mediante un navegador en tiempo real con Websockets, ZMQ y PHP en AWS

Lo que se pretende es implementar un Tablero de Monitoreo de Datos en Tiempo Real mediante un navegador Web. Supongamos por ejemplo que una empresa necesita estar viendo informacion en tiempo real de sus ventas , sus pedidos con envios pendientes o cualquier informacion que se actualice con frecuencia y se requiera que se actualice el tablero en el momento que exista algun cambio en la informacion. El objetivo sera que estos tableros o “dashboards” se actualicen en el momento que la informacion cambie.

Para la implementacion del tablero usaremos los siguientes Cloud Services de AWS:

  • Base de datos con la informacion que se pretende mostrar. En nuestro caso usaremos MariaDb con el servicio de RDS.
  • Servidor WEB apache montado en una Instancia EC2 con ami Linux II y PHP 7.4.
  • Servicio de Mensajeria ZMQ montado en la misma Instancia EC2 que el Servidor WEB.
  • Librería libsodium para usar encriptación en los mensajes

Configuracion de Instancia EC2

Nuestra instancia EC2 esta basada en una imagen Amazon Linux 2 AMI (HVM), SSD Volume Type , que a su vez esta basada en CentOS por lo que los comandos de instalacion corresponden a esta distribucion de Linux.

Debido a que se van a descargar y compilar las librerias libsodium y zeromq, debemos de asegurar de tener instalado el compilador gcc. Si no esta instalado podemos instalarlo utilizando el administrador de paquetes yum.

sudo yum install -y gcc gcc-c++

En primer lugar debemos descargar la libreria de encriptacion libsodium y la instalamos usando los comandos ./configure && make && sudo make install :

curl https://download.libsodium.org/libsodium/releases/LATEST.tar.gz | tar -xz
cd libsodium-stable
./configure && make && sudo make install
cd ../ 
sudo rm -rf libsodium-stable

Despues debemos descargar la libreria de mensajes ZMQ. Buscar la ultima version en https://github.com/zeromq/libzmq/releases , actualmente es la version 4.3.4 y porcedemos tambien a instalarla:

wget https://github.com/zeromq/libzmq/releases/download/v4.3.4/zeromq-4.3.4.tar.gz 
tar xfz zeromq-4.3.4.tar.gz && rm zeromq-4.3.4.tar.gz
cd zeromq-4.3.4
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig 
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
./configure && make && sudo make install
cd ../ 
sudo rm -rf zeromq-4.3.4.tar.gz 

A continuacion instalamos la extension ZMQ de PHP que nos permite comunicarnos con el servidor de mensajes. En este punto ya debemos de tener instalado nuestro servidor Apache , asi como PHP.

git clone git://github.com/mkoppanen/php-zmq.git
cd php-zmq
phpize
./configure && make && sudo make install
cd ../
sudo rm -rf php-zmq

Posteriormente se debe de agregar la extension zmq.so al final del archivo de configuracion de PHP, normalmente ubicado en /etc/php.ini y agregamos la siguiente linea al final del archivo.

extension=zmq.so

o si lo hacemos mediante script:

sudo chown ec2-user /etc/php.ini
echo extension=zmq.so >> /etc/php.ini
sudo chown root /etc/php.ini

Después tenemos que instalar una librería para implementar un Websocket con PHP. Para esto utilizaremos Ratchet , la cual se instala utilizando composer, agregándola a los paquetes requeridos usando el comando:

php ~/composer.phar require cboden/ratchet

Lo anterior, asumiendo que composer se encuentra en el directorio home (~).

O bien si no se tiene instalado composer, el script completo para instalarlo junto con la libreria Ratchet es:

cd ~
mkdir composer
cd composer
sudo curl -sS https://getcomposer.org/installer | sudo php
php ~/composer/composer.phar require cboden/ratchet
php ~/composer/composer.phar upgrade

Ratchet es una libreria de Websockets que esta construida encima de otra libreria de Sockets llamada React.

React maneja las conexiones y la Entrada/Salida para Ratchet. Además de React, que viene con Ratchet, necesitamos otra biblioteca que forma parte de la suite React: React/ZMQ. lo podemos agregar a composer con el comando:

php ~/composer.phar require react/zmq

Esta biblioteca vincula los sockets de ZeroMQ al núcleo de Reactor, lo que nos permitirá manejar tanto los sockets de WebSockets como los de ZeroMQ. Para instalar, su archivo composer.json debería verse así

{
     "autoload": {
         "psr-4": {
             "MyApp\": "src"
         }
     },
     "require": {
         "cboden/ratchet": "^0.4.3",
         "react/zmq": "0.2.|0.3."
     }
 }

Scripts utilizados

Supongamos que nueva información acaba de ser generada y queremos publicarla en nuestro tablero, lo que vamos a hacer es mediante un script de PHP mandar un mensaje con esta informacion a la misma instancia donde esta corriendo el script. Es decir, vamos a mandar un mensaje a localhost , en nuestro caso por el puerto 5555 con la informacion deseada. El codigo quedaria de la siguiente manera:

$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");

$entryData = array(
        'category' => "dashboardVentas"
         , 'when'     => "Fecha :".$fecha_actual
        , 'title'    => $newArray
        );

$entryData = json_encode($entryData);
$socket->send($entryData);  // Se publican los datos JSON via ZMQ

LIgas Adicionales

Libreria ZMQ

http://wiki.zeromq.org/bindings:php

http://wiki.zeromq.org/build:encryption

LIBRERIA LIBSODIUM

https://libsodium.gitbook.io/doc/

Libreria PHP ZMQ BINDING

https://www.php.net/zmq

LIBRERIA REACT PHP

https://reactphp.org

LIBRERIRA Ratchet PARA WebSockets CON PHP

http://socketo.me/

Servidor APACHE modulo de Websockets

https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

LIBRERIA AUTOBAHN EN JAVASCRIPT PARA WEBSOCKETS

https://crossbar.io/autobahn/

COMPOSER y PACKAGIST

https://phpenthusiast.com/blog/how-to-use-packagist-and-composer

AMI LINUX 2

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/amazon-linux-ami-basics.html

Google Analytics 4 y Google Tag Manager

Esta guía tiene como objetivo describir los pasos que se deben de hacer para configurar la nueva versión de Analytics GA4 en Google Tag Manager . Para esto voy a describir como funciona el proceso de envio de información y así quede mas claro el papel que juega cada pieza en este sistema.

Capa de Datos ( Data Layer )

Supongamos que cuentas con un sitio web ( vamos a asumir que es de comercio electrónico ) , sobre el cual quieres medir y visualizar la interacción que realizan los usuarios del mismo. Vas a querer monitorear lo que esta sucediendo en tu sitio, cosas tales como:

  • Que productos son los mas visitados ?
  • Que productos se agregaron al carrito de compra ?
  • Algún usuario se dio de alta en el registro e hizo login para hacer la compra ?
  • Alguien abandono el carrito antes de comprar ? y en que parte del proceso lo hizo ?

A cada una de las acciones anteriores las vamos a llamar eventos, y ademas cabe mencioar que estos son solo unos ejemplos de una gran cantidad de eventos que se pueden medir.

Nos pdriamos preguntar entonces, como podríamos registrar cada uno de los eventos que nos interesan ¿?

Bien, una forma de resolverlo es crear una variable en nuestro cliente , es decir , en el navegador , mediante Javascript y vamos a declarar esta variable del tipo arreglo (Array), de tal forma que cada elemento del arreglo corresponda a un único evento. Podríamos llamar a esta variable SeguimientoEventos , o datos , o bien como Google la ha llamado:  dataLayer. ( En español nos referimos a ella como Variable de Capa de Datos )

Entonces,  para inicializar la variable, tenemos que ejecutar el código: 

dataLayer= [];

En esta variable vamos a insertar los datos que correspondan a cada evento. Para esto vamos a definir por cada evento un objeto que tenga varias propiedades, de las cuales las mas lógicas serian:

evento = ( “se hizo click”, “se agrego al carrito”, “se realizo una compra”, etc. )

productos = ( información de los productos que se agregan )

Entonces, un evento puede ser cuando alguien ve los datos de un producto en particular, para lo que podemos usar la propiedad evento = “ver producto” y después mandar en la propiedad “productos” los datos del mismo. Este evento podría parecerse a:

objetoVerProducto = { ecommerce : { evento = “ver producto” }; { productos: [ { modelo=”el modelo” ; precio=”el precio”;  cantidad=”la cantidad”; masCaracteristicas = “masCaracteristicas” } ] } } }

Otro evento puede ser agregar un producto al carrito de compras, en cuyo caso el objeto podría ser:

objetoAgregarAlCarrito  = { ecommerce : { evento = “agregar al carrito” }; { productos: [ { modelo=”el modelo” ; precio=”el precio”;  cantidad=”la cantidad”; masCaracteristicas = “masCaracteristicas” } ] } } }

Los objetos anteriores contienen la propiedad ecommerce, la cual indica que se trata de un objeto del tipo de comercio electrónico, a su vez, este tiene la propiedad productos que puede contener solo un producto  o bien un arreglo de productos que están relacionados con el evento, y debe de tener otra propiedad evento que indique el tipo de evento del que se trate , en nuestros ejemplos serian “ver producto” y “agregar al carrito”.

Para ser congruentes con los nombres que se utilizan en la variable de capa de datos ( dataLayer ) de google, a la propiedad productos le llamaremos items , y a la propiedad evento le llamamos event . Asi mismo los parametros que hemos definido como modelo, precio, cantidad, deberan de llamarse item_name, price y quantity.

Además de estos parametros, hay muchos mas que vamos a utilizar para mandar información mas detallada del producto, tales como marca, variantes del producto, descuento, cupones, etc. Estos parametros , asi como los eventos pueden consultarse con mas detalle en la referencia de eventos de ecommerce de Google Analytics.

Hemos visto que por cada evento vamos a generar un objeto , pero que vamos a hacer con estos objetos ??

Cada que se genere un evento y queramos registrarlo , lo agregamos a nuestra variable dataLayer mediante el método push.  De tal forma que para agregar los 2 eventos anteriores deberíamos de hacer algo como:

dataLayer.push(objetoVerProducto);

dataLayer.push(objetoAgregarAlCarrito);

El resultado final será una variable dataLayer en la cual cada elemento del arreglo corresponde a un evento único. Esta variable se inicializa cada que se carga una pagina nueva. Un ejemplo de la variable dataLayer es la que se muestra en la siguiente imagen:

Aquí se puede observar que hay 6 elementos en la variable dataLayer , cuyos índices son del 0 al 5 y que los hemos impreso en la consola del navegador mediante el método forEach.

Los eventos con el índice 0 y 5 corresponden a 2 eventos como los que hemos venido mencionando y que son: “view_item_list” y “add_to_cart”, hasta aquí nada nuevo, sin embargo vemos que hay otros eventos en la variable cuyos índices son 1,2,3 y 4 y corresponden a los eventos “gtm.js”, “gtm.dom”, “gtm.load” y “gtm.linkClick”. Estos eventos adicionales que nosotros no hemos añadido intencionalmente usando el método push, son eventos que google registra de manera automática y que sirven para tener el timing correcto al activar los eventos. Por ejemplo, el evento “gtm.dom” se activa una vez que se ha cargado el DOM en la pagina. El evento “gtm.load” se activa una vez que se realizo la carga completa de la pagina web y asi otros eventos.

Los eventos que hemos definido nosotros se denominan Evento Personalizado, ya que no son los mismos en cada sitio web, es decir, el evento “add_to_cart” solo hace sentido en una pagina de ecommerce con carrito de compras. Pero no en una pagina de juegos donde los eventos seran mas del tipo “level_up” cuando un jugador sube de nivel.

Por otro lado, los eventos tales como la carga de pagina, cuando se termina de generar el DOM , o cuando se hace click en un elemento son comunes a todos los sitios web.

Tambien es importante saber que si hemos configurado la Medicion mejoarada (Enhanced measurement ) en nuestra propiedad de Analytics , entonces se habilita la medicion de eventos adicionales como los clicks, descargas de documentos, visualizacion de videos, paginas vistas, etc.

Que sigue ?

Ya tenemos nuestra variable de Capa de datos, la cual se crea cada vez que cargamos una pagina y se va actualizando conforme agreguemos objetos con nuestros eventos utilizando el metodo dataLayer.push .

Ahora, que papel juega Google Tag Manager en todo esto ?? Como es que Google utiliza esta esta informacion si la variable esta en nuestro navegador ??

Sigamos leyendo….

Vamos a definir ahora una funcion en Javascript que se dedique a identificar los cambios que existan en esta variable dataLayer, y cada vez que hagamos un push vamos a mandar esta informacion de manera asincrona a un servidor de Google. Este servidor vamos a llamarle un administrador de este dataLayer, o mjor aun , vamos a llamarle administrador de etiquetas, pero para eso hay que definir a que le llamamos etiqueta y en que momento decidimos activarla.

Administrador de Etiquetas ( Tag Manager )

Vamos a empezar diciendo que cada evento personalizado que se envía a este servidor, se identifica , pero no necesariamente se activa. Por lo que para activarse debemos definir un activador. Este activador, no es mas que una condición que se debe de cumplir para que la etiqueta se active. Por ejemplo, un activador podría llevarse a cabo cuando …

  • se haya terminado de cargar el DOM.
  • se haya cargado la pagina.
  • el nombre del evento sea igual a “add_to_cart” .
  • el nombre del evento sea igual a “view_item” .
  • el nombre del evento sea igual a “purchase” .
  • o cualquier combinacion de los anteriores.

Que hace el administrador de etiquetas cuando se cumplen las condiciones del activador ??

Basicamente lo que hace, es informar a un servicio de un tercero que se ha activado un evento y opcionalmente se pueden enviar los parametros adicionales que se deseen. Este servicio puede ser por ejemplo Google Analytics, Facebook Analytics, Linkedin, twitter, Quora, pinterest, etc.

Ok, entonces que es una etiqueta ?? Digamos que si queremos avisar a un servicio de que algo ha sucedido cada que se cumpla un activador , tendremos que definir una etiqueta. El tipo de servicio al cual le vamos a avisar lo conocemos como tipo de etiqueta. Asi ,una etiqueta básicamente consta de 2 partes: tipo de etiqueta y activador. En algunos casos el activador puede o no incluir eventos personalizados. Asi mismo esta etiqueta puede o no incluir parametros adicionales.

y es justamente aqui donde cobra importancia este administrador, ya que solo basta definir ( codificar ) una vez los eventos en un sitio web , y posteriormente, si queremos avisar de estos eventos a otros servicios, solamente tenemos que pedirle a este administrador que incluya a este nuevo servicio en los informes, creando una etiqueta con el mismo activador pero con una configuracion diferente. ( tipo de etiqueta distinto ).

Quizas esto quede mas claro con un ejemplo. Digamos que hemos codificado nuestro sitio para que al presionar el boton de agregar al carrito , haga un envio del producto que se ha agregado mendiante el metodo push. Como ya lo habiamos visto, esto sera: dataLayer.push(objetoAgregarAlCarrito);

por otro lado tenemos una etiqueta configurada del tipo Google Analytics: evento de GA4

y el activador esta definido como evento personalizado igual a “add_to_cart” , es decir, mientras que el evento tenga este nombre se va a activar la etiqueta.

Cuando la etiqueta se active, como esta configurada para un evento de GA4, lo que va a suceder, es que le va a informar a Analytics que se recibio un evento del tipo add to cart. Si revisamos ademas la informacion de los eventos de ecommerce, veremos que para el evento “add_to_cart” se requieren los parametros currency, items y value.

en la informacion de google, se nos muestra el siguiente ejemplo, donde podemos pareciar claramente el parametro items:

y si observamos bien , en la configuracion de la etiqueta nos menciona el tipo de eqtiqueta, el nombre de evento, el tipo de variable y el disparados ( trigger ). Hasta aqui todo bien. Pero nos falta revisar los parametros del evento; ahi nos menciona que debemos de mandar el parametro items y darle el valor {{Ecommerce items}}. Esta parte es muy importante ya que es la que le indica a Analytics toda la informacion contenida en la propiedad items. En el ejemplo de Google , esta informacion es el precio, la cantidad, el id del producto, la marca, etc.

Para pasar el parametro items a Analytics, debemos asegurarnos de incluirlo en los parametros del evento. Asi , si nos fijamos en la siguiente imagen, vemos en la seccion Parametros del Evento, el nombre de parametro items y el valor {{items}}

Esta parte, a mi forma de ver, no queda muy claro en la literatura de Google. Ya que uno supondria que al enviar el objeto ecommerce al administrador de etiquetas , este obtendria la informacion que viene en el objeto y la pasaria a Analytics o a cualquier otro tipo de Etiqueta. Pero no es asi, y si no pasamos esta informacion, Analytics, solo sabra que se realizo un evento “add_to_cart” pero no sabra que es lo que se agrego al carrito porque no cuenta con el paramtero items.

Espero haber sido claro en la explicacion, ya que aunque hay muchos tutoriales en internet sobre Google Tag Manager, aun es un producto muy reciente y hay cosas que no quedan claras sobre como interactúan todos los servicios. Es posible que mas adelante la herramienta vaya evolucionando y sea mas sencillo configurarla.

Referencias:

https://developers.google.com/tag-manager/ecommerce-ga4

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

Pasillo de Tecnologia 2020

Cuando tengo oportunidad de ir a alguna libreria en Estados Unidos , me gusta pasear por los pasillos del área de computacion para ver cuales son las tendencias en esta area. En años pasados era mas común encontrar libros de lenguajes de programación tradicionales como C, C#, C++, Java, Javscript, etc. asi como libros para Sitios Web que incluian PHP, MySql, JQuery y CSS , asi y otros tantos de frameworks de desarrollo. Se podian ver tambien libros para administradores de Redes y guias para certificaciones tipo CCNA.

En este Diciembre 2019, tuve también la oportunidad de darme una vuelta y note una tendencia muy marcada a una serie de temas que tienden a ser especializaciones dentro de las tecnologías de computo , no son temas nuevos, pero se aprecia como estos acaparan cada vez mas los estantes.

Entre estos temas destacan:

  • Ciberseguridad
  • Machine Learning
  • Arquitectos de Soluciones de AWS
  • Guias de Estudio para obtener Certificaciones en los anteriores

Es recomendable tomar nota de estas tendencias, ya que de alguna manera nos indican hacia donde se dirige el campo de accion de los profesionales en estas areas y sobre todo en donde estaran las oportunidades laborares en los proximos años.

En una conferencia de seguridad se mencionó el dato de que , para el año 2022 habrá una escasez de 1.8 millones de trabajadores en el área de Ciberseguridad.

También vale la pena comentar como en EU, así como en otros países de Europa, la programación es parte de la educación básica, mientras en países de América Latina sigue siendo un tema solo para Nerds.

Citando a Steve Jobs, “Everybody in this country should learn to program a computer, because it teaches you how to think.”

Links:

https://www.theguardian.com/technology/2014/sep/04/coding-school-computing-children-programming