El Stack de Monitoreo Moderno

Prometheus y Grafana forman el stack de monitoreo open-source estándar de la industria. Prometheus recolecta y almacena métricas de series temporales, mientras Grafana las visualiza a través de dashboards personalizables. Para ingenieros QA, este stack proporciona insights en tiempo real sobre rendimiento de aplicaciones, salud de infraestructura y métricas de experiencia de usuario.

¿Por qué Prometheus + Grafana?

  • Modelo Pull-Based - Prometheus extrae métricas de targets, no se necesita push desde el cliente
  • Lenguaje de Consulta Poderoso (PromQL) - Consultas flexibles y agregación de métricas
  • Service Discovery - Descubrimiento automático de targets en entornos dinámicos (Kubernetes, AWS, etc.)
  • Alertas - Alert manager integrado con enrutamiento y silenciamiento
  • Open Source - Sin vendor lock-in, gran soporte comunitario
  • Visualización Grafana - Dashboards ricos con soporte multi data source

Arquitectura Prometheus

Componentes Principales

# Resumen arquitectura Prometheus
components:
  prometheus_server:
    - scrapes_metrics: true
    - stores_timeseries: true
    - evaluates_rules: true

  exporters:
    - node_exporter: "Métricas sistema (CPU, memoria, disco)"
    - blackbox_exporter: "Probar endpoints (HTTP, DNS, TCP)"
    - custom_exporters: "Métricas específicas de aplicación"

  pushgateway:
    - for_batch_jobs: true
    - short_lived_processes: true

  alertmanager:
    - handles_alerts: true
    - routes_notifications: true
    - silences_alerts: true

  service_discovery:
    - kubernetes: true
    - consul: true
    - ec2: true
    - dns: true

Instalar Prometheus

# Instalación Docker
docker run -d \
  --name prometheus \
  -p 9090:9090 \
  -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
  prom/prometheus

# Instalación Kubernetes (usando Helm)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/prometheus

# Archivo configuración: prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']

  - job_name: 'application'
    static_configs:
      - targets: ['app:8080']
    metrics_path: '/metrics'

Instrumentar Aplicaciones

Aplicación Node.js

// app.js
const express = require('express');
const promClient = require('prom-client');

const app = express();
const register = promClient.register;

// Habilitar métricas por defecto (CPU, memoria, event loop lag)
promClient.collectDefaultMetrics({ register });

// Métricas personalizadas
const httpRequestDuration = new promClient.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duración de solicitudes HTTP en segundos',
  labelNames: ['method', 'route', 'status_code'],
  buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10]
});

const httpRequestTotal = new promClient.Counter({
  name: 'http_requests_total',
  help: 'Total de solicitudes HTTP',
  labelNames: ['method', 'route', 'status_code']
});

const activeConnections = new promClient.Gauge({
  name: 'active_connections',
  help: 'Número de conexiones activas'
});

// Middleware para rastrear métricas
app.use((req, res, next) => {
  const start = Date.now();
  activeConnections.inc();

  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;

    httpRequestDuration
      .labels(req.method, req.route?.path || req.path, res.statusCode)
      .observe(duration);

    httpRequestTotal
      .labels(req.method, req.route?.path || req.path, res.statusCode)
      .inc();

    activeConnections.dec();
  });

  next();
});

// Endpoint métricas
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', register.contentType);
  res.end(await register.metrics());
});

// Lógica negocio
app.get('/api/users', async (req, res) => {
  // Tu lógica aquí
  res.json({ users: [] });
});

app.listen(3000, () => {
  console.log('Servidor ejecutando en puerto 3000');
  console.log('Métricas disponibles en http://localhost:3000/metrics');
});

PromQL: El Lenguaje de Consulta

Consultas Básicas

# Vector instantáneo - valor actual
http_requests_total

# Filtrar por labels
http_requests_total{method="GET", status_code="200"}

# Vector de rango - valores a lo largo del tiempo
http_requests_total[5m]

# Tasa de incremento (por segundo)
rate(http_requests_total[5m])

# Incremento durante período de tiempo
increase(http_requests_total[1h])

PromQL Avanzado

# Tasa de solicitudes por endpoint
sum(rate(http_requests_total[5m])) by (route)

# Porcentaje tasa de error
(
  sum(rate(http_requests_total{status_code=~"5.."}[5m]))
  / sum(rate(http_requests_total[5m]))
) * 100

# Latencia P95
histogram_quantile(0.95,
  rate(http_request_duration_seconds_bucket[5m])
)

# Porcentaje disponibilidad
(
  sum(up{job="application"})
  / count(up{job="application"})
) * 100

# Tasa crecimiento uso memoria
deriv(node_memory_MemAvailable_bytes[1h])

Dashboards Grafana

Instalar Grafana

# Instalación Docker
docker run -d \
  --name=grafana \
  -p 3000:3000 \
  grafana/grafana

# Añadir data source Prometheus
# Navegar a: http://localhost:3000 (admin/admin)
# Configuration → Data Sources → Add Prometheus
# URL: http://prometheus:9090

Crear Dashboard de Rendimiento

{
  "dashboard": {
    "title": "Rendimiento Aplicación",
    "panels": [
      {
        "title": "Tasa Solicitudes",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total[5m])) by (route)",
            "legendFormat": "{{route}}"
          }
        ],
        "type": "graph"
      },
      {
        "title": "Tasa Error",
        "targets": [
          {
            "expr": "(sum(rate(http_requests_total{status_code=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))) * 100",
            "legendFormat": "Error %"
          }
        ],
        "type": "graph"
      }
    ]
  }
}

Alertas con Prometheus & Grafana

Reglas de Alerta Prometheus

# alerts.yml
groups:
  - name: performance_alerts
    interval: 30s
    rules:
      - alert: TasaErrorAlta
        expr: |
          (sum(rate(http_requests_total{status_code=~"5.."}[5m]))
          / sum(rate(http_requests_total[5m]))) * 100 > 5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Tasa error alta detectada"
          description: "Tasa error es {{ $value }}% (umbral: 5%)"

      - alert: LatenciaAlta
        expr: |
          histogram_quantile(0.95,
            rate(http_request_duration_seconds_bucket[5m])
          ) > 2
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Latencia alta en {{ $labels.route }}"
          description: "Latencia P95 es {{ $value }}s"

Mejores Prácticas Monitoreo

Las Cuatro Señales Doradas

# 1. LATENCIA - Duración solicitud
histogram_quantile(0.99,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)

# 2. TRÁFICO - Tasa solicitud
sum(rate(http_requests_total[5m]))

# 3. ERRORES - Tasa error
sum(rate(http_requests_total{status_code=~"5.."}[5m]))

# 4. SATURACIÓN - Utilización recursos
avg(rate(node_cpu_seconds_total{mode!="idle"}[5m])) * 100

Conclusión

Prometheus y Grafana proporcionan un stack de monitoreo poderoso y flexible para ingenieros QA. Desde instrumentar aplicaciones hasta crear dashboards perspicaces y configurar alertas inteligentes, este stack habilita monitoreo proactivo de rendimiento y detección rápida de problemas.

Conclusiones Clave:

  • Instrumentar aplicaciones con métricas personalizadas
  • Dominar PromQL para consultas poderosas
  • Crear dashboards accionables con Grafana
  • Configurar alertas basadas en SLOs/SLIs
  • Seguir metodologías monitoreo: RED, USE, Cuatro Señales Doradas
  • Integrar monitoreo en workflows de pruebas de carga

El monitoreo efectivo no es solo recolectar métricas — es convertir datos en insights accionables.