blog

elastic apm

Guía práctica: Application Performance Monitoring con Elastic APM

Tan importante como desarrollar una app que nos acerque a nuestros clientes es velar porque esta funcione correctamente y sin errores. Por eso es fundamental contar con herramientas que nos permitan identificar problemas de rendimiento o que afecten a la experiencia del usuario, realizando diagnósticos que nos permitan realizar las correcciones oportunas.

Esto es lo que nos permite un APM: un tipo de herramienta muy potente que se encarga de monitorizar cada aplicación, comprobando que todo funcione según lo previsto.

De esto, y en concreto, de Elastic APM, te hablamos a continuación.

¿Qué es Application Performance Monitoring (APM)?

APM, por sus siglas en inglés Application Performance Monitoring, se refiere a un servicio de monitorización de rendimiento de aplicaciones. Básicamente se trata de un servicio que recibe datos de transacciones y otros trabajos realizados en nuestra aplicación, permitiendo obtener métricas tales como medias de latencias de nuestros endpoints, de nuestras consultas a base de datos, media de respuestas HTTP, etc.

En resumen, permiten trazar y gestionar el rendimiento de nuestra aplicación, permitiendo realizar acciones correctivas tempranas gracias a la observación en tiempo real de lo que está sucediendo en nuestra aplicación.

¿Qué es Elastic APM?

El servicio Elastic APM entra dentro de la gama de productos de Elastic llamado Observability. Esta gama de productos unifica logs, métricas y trazas de APM en un mismo panel de Kibana.

Entre otras muchas cosas, Elastic APM nos permite monitorizar cosas como:

• Media de latencias
• Rendimiento de la app (transacciones por segundo)
• Transacciones (con su latencia media, tps, ratio de error e impacto)
• Ratios de error
• Lista de errores
• Traza completa de cada transacción (traza de cada request)

Y no solo esto: también permite generar alertas y reglas, de forma que podamos enterarnos antes ante un comportamiento anómalo de la aplicación.

¿Qué se necesita para usar Elastic APM?

Para poder monitorizar nuestra aplicación en Elastic APM necesitamos los siguientes servicios:

• Servicio Elastic APM
• Servicio Elasticsearch
• Servicio Kibana

También se necesita el Agente del servicio que se necesita monitorizar.

Puesta en marcha del APM

Se podría tener acceso a los 3 servicios necesarios directamente hospedados en Elastic Cloud, pero en este caso nos vamos a centrar en hospedar los servicios nosotros mismos. Es más, usaremos Docker para hacer un PoC (proof of concept).

version: "3.1"

services:
    apm-server:
        image: docker.elastic.co/apm/apm-server:7.14.1
        depends_on:
            elasticsearch:
                condition: service_healthy
            kibana:
                condition: service_healthy
        cap_add: ["CHOWN", "DAC_OVERRIDE", "SETGID", "SETUID"]
        cap_drop: ["ALL"]
        ports:
            - 8200:8200
        networks:
            - elastic
        command: >
            apm-server -e
              -E apm-server.rum.enabled=true
              -E setup.kibana.host=kibana:5601
              -E setup.template.settings.index.number_of_replicas=0
              -E apm-server.kibana.enabled=true
              -E apm-server.kibana.host=kibana:5601
              -E output.elasticsearch.hosts=["elasticsearch:9200"]
        healthcheck:
            interval: 10s
            retries: 12
            test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8200/

    elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:7.14.1
        environment:
            - bootstrap.memory_lock=true
            - cluster.name=docker-cluster
            - cluster.routing.allocation.disk.threshold_enabled=false
            - discovery.type=single-node
            - ES_JAVA_OPTS=-XX:UseAVX=2 -Xms1g -Xmx1g
        ulimits:
            memlock:
                hard: -1
                soft: -1
        volumes:
            - esdata:/usr/share/elasticsearch/data
        ports:
            - 9200:9200
        networks:
            - elastic
        healthcheck:
            interval: 20s
            retries: 10
            test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"'

    kibana:
        image: docker.elastic.co/kibana/kibana:7.14.1
        depends_on:
            elasticsearch:
                condition: service_healthy
        environment:
            ELASTICSEARCH_URL: http://elasticsearch:9200
            ELASTICSEARCH_HOSTS: http://elasticsearch:9200
        ports:
            - 5601:5601
        networks:
            - elastic
        healthcheck:
            interval: 10s
            retries: 20
            test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status

volumes:
    esdata:
        driver: local

networks:
    elastic:
        driver: bridge

 

¿Donde encontramos los Agentes?

Lo siguiente sería configurar el agente de PHP que envía los distintos eventos que queremos monitorizar. Elastic APM cuenta con su propio agente PHP (en forma de extensión de PHP), pero es complejo y demasiado automatizado (más info de este agente: Elastic APM Agent).

Existe otra alternativa que es mucho más funcional que este agente: ZoiloMora APM PHP Agent, y que es usado por los chicos de Pccomponentes. No es más que una implementación del API de eventos que provee APM. Este agente necesita de otros módulos para monitorizar todos los componentes de nuestra aplicación.

Hasta el momento se han currado estos:

Custom reports

Transaction Wrappers

HTTP Clients

Databases

Others

Prácticamente todos son compatibles con PHP8 y la última versión de Symfony (hasta la fecha, Symfony 5.3).

¿Cómo configurar APM sobre una aplicación Symfony 5.3?

En nuestro .env.local:

...
APM_SERVER_URL=http://192.168.3.44:8200 # APM SERVER URL
APM_SERVICE_NAME="Name APM Service" # APM SERVICE NAME

Es tan fácil como setear los siguientes servicios:

# services.yaml
services:
    # APM Tracer config
    apm.configuration:
        class: \ZoiloMora\ElasticAPM\Configuration\CoreConfiguration
        arguments:
            - { appName: '%env(resolve:APM_SERVICE_NAME)%', stacktraceLimit: 50 }

    apm.reporter:
        class: \ZoiloMora\ElasticAPM\Reporter\ApmServerCurlReporter
        arguments:
            - '%env(resolve:APM_SERVER_URL)%'

    apm.poolFactory:
        class: \ZoiloMora\ElasticAPM\Pool\Memory\MemoryPoolFactory
        calls:
            - method: create

    apm.tracer:
        class: \ZoiloMora\ElasticAPM\ElasticApmTracer
        arguments:
            $coreConfiguration: '@apm.configuration'
            $reporter: '@apm.reporter'
            $poolFactory: '@apm.poolFactory'

A partir de este momento ya tendremos disponible la instancia del tracer en nuestra aplicación.

Configuración del APM Tracer para Symfony Messenger

# services.yaml
services:
    # Messenger APM
    app.bus.middleware.apm:
        class: PcComponentes\ElasticAPM\Symfony\Component\Messenger\ApmMiddleware
        arguments:
            $elasticApmTracer: '@apm.tracer' # Instancia APM Tracer
            $nameExtractor: '@app.bus.middleware.apm.name_extractor'

    app.bus.middleware.apm.name_extractor:
        class: Nidum\Shared\Infrastructure\Messenger\APMTextNameExtractor

Configuración del APM Tracer para HTTPKernel

# services.yaml
services:
    # HttpKernel APM
    PcComponentes\ElasticAPM\Symfony\Component\HttpKernel\EventSubscriber:
        class: PcComponentes\ElasticAPM\Symfony\Component\HttpKernel\EventSubscriber
        autoconfigure: true
        arguments:
            $router: '@router'
            $elasticApmTracer: '@apm.tracer' # Instancia APM Tracer

Configuración del APM Tracer para comandos de consola

# services.yaml
services:
    # Console APM
    PcComponentes\ElasticAPM\Symfony\Component\Console\EventSubscriber:
        class: PcComponentes\ElasticAPM\Symfony\Component\Console\EventSubscriber
        autoconfigure: true
        arguments:
            $elasticApmTracer: '@apm.tracer' # Instancia APM Tracer

Configuración del APM Tracer para Doctrine DBAL

# services.yaml
services:
    # Inyecta el SQLLogger de APM en el loggerChain por defecto (manteniendo los dos actuales)
    doctrine.dbal.logger.chain.default:
        class: Doctrine\DBAL\Logging\LoggerChain
        arguments:
            - { sqlLogger1: '@doctrine.dbal.logger.profiling.default', sqlLogger2: '@doctrine.dbal.logger', sqlLogger3: '@apm.dbal' }

    apm.dbal:
        class: PcComponentes\ElasticAPM\Doctrine\DBAL\Logging\SQLLogger
        arguments:
            $elasticApmTracer: '@apm.tracer' # Instancia APM Tracer
            $instance: 'test'
            $engine: 'mysql'

Configuración del APM Tracer para Symfony HTTP Client

# services.yaml
services:
    amp.http_client:
        class: PcComponentes\RuleStorm\Infrastructure\TraceableApmHttpClient
        arguments:
            $client: '@http_client'
            $elasticApmTracer: '@apm.tracer' # Instancia APM Tracer

Conclusiones

Si todo se ha configurado correctamente, tendríamos nuevos datos en la sección Observability >> APM >> Services de nuestro kibana (http://localhost:5601/).    

Y con esto podríamos tracear una petición al completo:

Disponemos de absolutamente todos los datos que dio origen la petición:

Incluso, tracear una excepción (error 500) ocurrida en nuestra aplicación:

Mediciones Extras: Filebeat & Metricbeat

Y por si no fuese suficiente con monitorizar el APM de nuestra app a través de Kibana, podemos usar otros dos servicios de Elastic, que dotarán a nuestro panel de Kibana de muchísima más información para analizar y prevenir errores:

  • Metricbeat: este servicio se usa para poder medir el comportamiento y estado de la infraestructura que soporta nuestros aplicativos.
  • Filebeat: este servicio de Elastic se usa para registrar y gestionar los logs que llega a generar nuestro aplicativo: apache, mysql…

Filebeat

Permite enviar los eventos tipo log para visualizarlos en Kibana (más info en https://www.elastic.co/es/beats/filebeat).

Instalación y configuración

Tan fácil como:

curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.14.1-amd64.deb 
dpkg -i filebeat-7.14.1-amd64.deb 

filebeat modules enable apache 
service filebeat start

Recordad editar el archivo /etc/filebeat/filebeat.yml y poner los parámetros host de elastic y kibana.

Metricbeat

Mide el comportamiento y el estado de la infraestructura que soporta nuestra aplicación (más info en https://www.elastic.co/es/beats/metricbeat).

Instalación y configuración

Tan fácil como:

curl -L -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-7.14.1-amd64.deb && \
dpkg -i metricbeat-7.14.1-amd64.deb && \

metricbeat modules enable apache && \
service metricbeat start

Recordad editar el archivo /etc/metricbeat/metricbeat.yml y los parámetros host de Elastic y Kibana.