====== Monitorización de aplicaciones ======
{{grafana_logo.jpg?125 }}
{{ prometheus_logo.png?220}}
{{ dashboard.png }} Dashboard de Grafana (Fuente: https://grafana.com/blog/2023/10/10/how-to-embed-grafana-dashboards-into-web-applications/
===== Instalar Grafana y Prometheus ===== Lanzaremos [[https://es.wikipedia.org/wiki/Grafana|Grafana]] y [[https://en.wikipedia.org/wiki/Prometheus_(software)|Prometheus]] como contenedores docker, configurados en una red para que puedan verse el uno al otro. Al mismo tiempo publicaremos los puertos sobre la máquina local para poder acceder a sus interfaces web: version: "3" services: prometheus: image: prom/prometheus ports: - 9090:9090 volumes: - ./prometheus_data:/prometheus - ./prometheus.yml:/etc/prometheus/prometheus.yml command: - "--config.file=/etc/prometheus/prometheus.yml" extra_hosts: - "host.docker.internal:192.168.1.120" # coloca aqui la IP local de tu equipo networks: - localprom grafana: image: grafana/grafana-enterprise ports: - 3000:3000 volumes: - ./grafana_data:/var/lib/grafana extra_hosts: - "host.docker.internal:192.168.1.120" # coloca aqui la IP local de tu equipo networks: - localprom depends_on: - prometheus networks: localprom: driver: bridge Hay que tener en cuenta que: * ''Grafana'' quedará accesible en http://localhost:3000 * ''Prometheus'' quedará accesible en http://localhost:9090 A su vez dejaremos este fichero, ''prometheus.yml'' en la carpeta raíz de nuestro proyecto. Ahi configuramos donde escuchan prometheus y el servicio que estamos monitorizando: global: scrape_interval: 5s scrape_configs: - job_name: "prometheus_service" static_configs: - targets: ["host.docker.internal:9090"] - job_name: "nodejs_service" static_configs: - targets: ["host.docker.internal:8080"] ===== Integrar Grafana con Node.js ===== Ahora tendremos que facilitar un endpoint ''/metrics'' en nuestro servicio para que Prometheus pueda extraer las métricas de nuestro servicio haciendo peticiones al mismo. Primero, añadimos la librería de Prometheus para nuestra aplicación: "dependencies": { . . . "prom-client": "^15.1.3" }, Y definimos una serie de métricas en el fichero ''config/metrics.js''. Más adelante las haremos accesible como respuesta en el endpoint ''/metrics'' que vamos a publicar: 'use strict'; const promClient = require('prom-client'); // Crea un histograma para registrar la duración de las peticiones HTTP en segundos const httpRequestDurationSeconds = new promClient.Histogram({ name: 'http_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'path', 'code'], }); // Crea un contador de peticiones HTTP totales const httpRequestsTotal = new promClient.Counter({ name: 'http_requests_total', help: 'How many HTTP requests processed, partitioned by status code, method, and HTTP path', labelNames: ['method', 'path', 'code'], }); // Crea una medición de las peticiones HTTP en vuelo const inFlightRequests = new promClient.Gauge({ name: 'http_requests_in_flight', help: 'Current number of in-flight HTTP requests', }); module.exports = { httpRequestDurationSeconds, httpRequestsTotal, inFlightRequests, }; En nuestro fichero principal, ''app.js'', configuraremos lo necesario para recoger las métricas que hemos configurado antes y publicaremos el nuevo endpoint ''/metrics'' que las dejará accesibles para Prometheus, que es quién las recoge y almacena. También llamaremos a ''promClient.collectDefaultMetrics()'' que recoge algunas métricas ya establecidas por defecto que quizás nos pueda interesar también mostrar en los Dashboards que haremos con Grafana. const promClient = require('prom-client'); const { httpRequestDurationSeconds, httpRequestsTotal, inFlightRequests } = require('./config/metrics'); . . . // Recoge métricas por defecto promClient.collectDefaultMetrics(); . . . // Recoger las métricas configuradas en config/metrics app.use((req, res, next) => { // Anota la request en vuelo inFlightRequests.inc(); // Inicia un timer para comenzar a calcular la duración de la request const end = httpRequestDurationSeconds.startTimer(); const method = req.method; const path = req.route ? req.route.path : req.path; // Cada vez que una request termina, se recogen las métricas configuradas res.on('finish', () => { const statusCode = res.statusCode; // Captura la duración de la petición end({ method, path, code: statusCode }); // Incrementa el contador de peticiones HTTP httpRequestsTotal.inc({ code: statusCode, method: method.toLowerCase(), path: path }); // Decrementa el contador de peticiones en vuelo inFlightRequests.dec(); }); next(); }); // Define el endpoint que usará prometheus para recoger las métricas app.get('/metrics', async(req, res) => { try { res.set('Content-Type', promClient.register.contentType); res.end(await promClient.register.metrics()); } catch (error) { res.status(500).end(error); } }); . . . app.use('/', cities); . . . En http://localhost:8080/metrics ya podremos visualizar las métricas (como texto plano)
{{ metrics.png }} Métricas de nuestro servicio Node.js
===== Comprobar la configuración de Prometheus ===== Antes de seguir, para comprobar que todo está funcionando bien, podemos echar un vistazo en Prometheus y verificar que tiene acceso a las métricas que nuestro servicio publica a través del endpoint ''/metrics'' que acabamos de configurar: Status -> Targets
{{ prometheus.png }} Configuración de Prometheus en http://localhost:9090
===== Configurar un dashboard en Grafana ===== ==== Añadir Prometheus como connection ==== Ahora, accediendo al interfaz web de Grafana (http://localhost:3000), configuraremos a Prometheus como un nuevo conector ya que proporcionará datos para los Dashboards que queremos diseñar en Grafana. Accedemos a ''Connection -> Add new connection -> Prometheus''
{{ grafana_add_connection.png }} Añadir una nueva connection en Grafana
Y pulsamos ''Save & test'' para darlo por configurado ==== Crear un dashboard y visualizaciones ==== El último paso será crear un nuevo Dashboard y añadir todas las visualizaciones (gráficos) que precisemos. Por ejemplo: * Peticiones por segundo * Tasa de fallos * Códigos de estado como respuestas * Tiempo de respuesta
{{ my_dashboard.png }} Grafana dashboard
---- (c) 2025 Santiago Faci