Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monitoreo y Observabilidad — ICC-443 PUCMM

Proyecto didáctico que demuestra los tres pilares de la observabilidad en una aplicación Spring Boot.

Contenido del curso

# Tema Archivo
00 ¿Qué es la observabilidad? Monitoring vs. Observability. Los 3 pilares. Pull vs. Push. SLI/SLO/SLA. docs/00-observabilidad.md
01 Métricas con Prometheus y Micrometer. Counter, Gauge, Histogram. PromQL. Cardinalidad. docs/01-metricas.md
02 Trazas distribuidas con OpenTelemetry y Tempo. Spans, TraceContext, Sampling, TraceQL. docs/02-trazas.md
03 Logs con Loki. Logs estructurados. LogQL. Loki vs. Elasticsearch. Correlación log→traza. docs/03-logs.md
04 Alertas con Prometheus y AlertManager. Reglas PromQL. Routing. Silencing. Inhibition. docs/04-alertas.md
05 Arquitectura de producción. Mismo servidor vs. servidor separado. Seguridad. Checklist. docs/05-produccion.md

Proyecto didáctico — implementación:

Señal Herramienta Modelo Protocolo
Métricas Prometheus + Grafana Pull HTTP scraping
Trazas Tempo + Grafana Push OTLP (gRPC/HTTP)
Logs Loki + Grafana Push OTLP (HTTP)

Arquitectura

┌──────────────────────────────────────────────────────────────────┐
│                     MISMO SERVIDOR (modo didáctico)              │
│                                                                  │
│  ┌────────────────────┐      PULL      ┌──────────────────────┐  │
│  │  Spring Boot :8080 │ ◄─── scrape ── │  Prometheus :9090    │  │
│  │  /actuator/        │                │  (métricas)          │  │
│  │  prometheus        │                └──────────┬───────────┘  │
│  │                    │                           │ remote_write │
│  │                    │  PUSH (OTLP)  ┌──────────▼───────────┐   │
│  │                    │ ──────────►   │  Alloy :4317/:4318   │   │
│  └────────────────────┘               │  (colector)          │   │
│                                       └──────┬───────────────┘   │
│                                              │                   │
│                               ┌─────────────┼──────────────┐     │
│                               │             │              │     │
│                          traces          logs          metrics   │
│                               │             │              │     │
│                        ┌──────▼──┐  ┌───────▼──┐           │     │
│                        │ Tempo   │  │  Loki    │           │     │
│                        │ :3200   │  │  :3100   │           │     │
│                        └──────┬──┘  └───────┬──┘           │     │
│                               │             │              │     │
│                        ┌──────▼─────────────▼─────────────▼─┐    │
│                        │         Grafana :3000              │    │
│                        │  (métricas + trazas + logs)        │    │
│                        └────────────────────────────────────┘    │
│                                                                  │
│  ┌───────────────────────────────┐                               │
│  │  AlertManager :9093           │ ◄── alertas de Prometheus     │
│  └───────────────────────────────┘                               │
└──────────────────────────────────────────────────────────────────┘

Inicio rápido

1. Levantar el stack de telemetría

docker compose up -d

2. Iniciar la aplicación Spring Boot

./mvnw spring-boot:run

La app corre en http://localhost:8080
La variable OTEL_EXPORTER_HOST=localhost (default) apunta a Alloy local.

3. Generar tráfico

# Crear pedidos (genera métricas + trazas + logs)
curl -X POST "http://localhost:8080/api/orders?productId=PROD-001"

# Operación lenta (dispara alerta de latencia en ~5 min)
curl http://localhost:8080/api/orders/slow

# Error controlado (dispara alerta de error rate en ~2 min)
curl http://localhost:8080/api/orders/error

# Evento de negocio con duración custom
curl -X POST "http://localhost:8080/api/orders/events?type=shipment&durationMs=200"

# Ver métricas crudas de Prometheus
curl http://localhost:8080/actuator/prometheus | grep demo_

4. Explorar en Grafana

Abrir http://localhost:3000 (admin/admin)

Dashboard Qué muestra
Spring Boot Starter Métricas JVM, HTTP, threads
Monitoring Service Health Error rate, latencia P95/P99, disponibilidad
Monitoring Logs Deep Dive Logs con filtro por nivel, mensaje, correlación
Monitoring Traces Deep Dive Trazas distribuidas, gantt chart por petición
Monitoring Service Unified Vista combinada métricas + trazas + logs
Monitoring Operations Resumen operacional general
Observability Platform Health Estado de Prometheus, Loki, Tempo, Alloy

Estructura del proyecto

monitoring/
├── src/main/java/edu/pucmm/monitoring/
│   ├── MonitoringApplication.java         # Entrada + @ConfigurationPropertiesScan
│   ├── config/
│   │   ├── TelemetryConfig.java           # MeterRegistryCustomizer (tags globales)
│   │   └── TelemetryProperties.java       # @ConfigurationProperties("monitoring.telemetry")
│   ├── controller/
│   │   └── OrderController.java           # Endpoints de demostración
│   └── service/
│       └── OrderService.java              # Métricas custom: Counter, Timer, @Timed
│
├── telemetry/
│   ├── prometheus/
│   │   ├── prometheus.yml                 # Scrape config + alerting
│   │   └── rules/app-alerts.yml          # Reglas de alerta PromQL
│   ├── loki/loki.yaml                     # Config de Loki (almacenamiento de logs)
│   ├── tempo/tempo.yaml                   # Config de Tempo (almacenamiento de trazas)
│   ├── alloy/
│   │   ├── config.alloy                   # Alloy modo mismo servidor (all-in-one)
│   │   └── agent.alloy                    # Alloy modo agente remoto (servidor separado)
│   ├── alertmanager/alertmanager.yml      # Enrutamiento de alertas
│   └── grafana/
│       ├── provisioning/
│       │   ├── datasources/datasources.yml  # Prometheus + Tempo + Loki
│       │   └── dashboards/dashboards.yaml   # Carpeta de dashboards
│       └── dashboards/                    # Archivos JSON de dashboards
│
├── docker-compose.yml                     # Stack completo de observabilidad
└── src/main/resources/application.yml    # Config de la app con telemetría

Conceptos clave por componente

Spring Boot Actuator

Expone endpoints de gestión. El más importante para observabilidad:

  • GET /actuator/prometheus — métricas en formato Prometheus text

Micrometer + Prometheus (Métricas)

Modelo Pull: Prometheus va a buscar las métricas cada 15 segundos.

Tres formas de crear métricas custom:

// 1. Anotación declarativa (más simple)
@Timed(value = "demo_create_seconds", description = "Tiempo de creación")
public void create() { ... }

// 2. Counter (cuenta eventos)
Counter.builder("demo_orders_total").register(registry).increment();

// 3. Timer con histograma (mide duración y calcula percentiles)
Timer.builder("demo_processing_seconds").register(registry).record(() -> {
    // lógica de negocio
});

OpenTelemetry + Alloy (Trazas y Logs)

Modelo Push: la app envía activamente sus trazas y logs a Alloy.

  • spring-boot-starter-opentelemetry instrumenta automáticamente HTTP, JDBC, etc.
  • OTEL_EXPORTER_HOST controla hacia dónde se envían las señales.
  • Sampling en application.yml: 1.0 = 100% (didáctico), 0.1 = 10% (producción).

Alloy (Grafana Agent)

Colector de telemetría que:

  1. Recibe OTLP de la app (puerto 4317/4318)
  2. Enriquece los logs con labels para Loki
  3. Reenvía trazas a Tempo
  4. Reenvía logs a Loki
  5. Descubre y recolecta logs de contenedores Docker

Correlación entre señales

La observabilidad real viene de poder cruzar las tres señales:

  • Métrica anómala → buscar trazas de ese período → revisar logs de esa traza
  • Error en log → ir a la traza completa → ver en qué servicio falló
  • Traza lenta → correlacionar con métricas de CPU/memoria del momento

Modo Servidor Separado (producción)

En producción, el stack de telemetría corre en un servidor diferente al de la app.

Qué cambia en la app

Solo una variable de entorno:

# Antes (mismo servidor):
OTEL_EXPORTER_HOST=localhost

# Después (servidor separado):
OTEL_EXPORTER_HOST=192.168.1.100   # IP del servidor de telemetría

Configuración de Alloy en el servidor de la app

Usar telemetry/alloy/agent.alloy en lugar de config.alloy:

docker run \
  -v ./telemetry/alloy/agent.alloy:/etc/alloy/config.alloy \
  -p 4317:4317 -p 4318:4318 \
  -e CENTRAL_ALLOY_OTLP_GRPC_ENDPOINT=192.168.1.100:4317 \
  -e CENTRAL_LOKI_PUSH_URL=http://192.168.1.100:3100/loki/api/v1/push \
  -e DEPLOYMENT_ENVIRONMENT=prod \
  -v /var/run/docker.sock:/var/run/docker.sock \
  grafana/alloy:latest run /etc/alloy/config.alloy

Qué cambia en el servidor de telemetría

El prometheus.yml necesita apuntar a la IP del servidor de la app:

scrape_configs:
  - job_name: app
    static_configs:
      - targets: ["192.168.1.50:8080"]  # IP del servidor de la app

Diagrama modo separado

[Servidor App :IP_A]          [Servidor Telemetría :IP_T]
┌──────────────────────┐      ┌────────────────────────────┐
│  Spring Boot :8080   │      │  Alloy (central) :4317     │
│  Alloy (agente)      │─────►│  Tempo           :3200     │
│    :4317/:4318       │ WAN  │  Loki            :3100     │
└──────────────────────┘      │  Prometheus      :9090     │
         ▲                    │  Grafana         :3000     │
         │ scraping           │  AlertManager    :9093     │
         └────────────────────┤                            │
                              └────────────────────────────┘

Puertos de referencia

Puerto Servicio Propósito
8080 Spring Boot App API REST + /actuator/prometheus
3000 Grafana Dashboards
9090 Prometheus UI + PromQL
3200 Tempo API de trazas
3100 Loki API de logs
4317 Alloy OTLP gRPC receiver
4318 Alloy OTLP HTTP receiver
12345 Alloy UI de diagnóstico
9093 AlertManager UI + API

Queries de ejemplo

PromQL (Prometheus / Grafana)

# Tasa de peticiones HTTP por segundo
rate(http_server_requests_seconds_count{application="monitoring-demo"}[5m])

# Latencia P95
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, uri))

# Tasa de errores
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/ sum(rate(http_server_requests_seconds_count[5m]))

# Pedidos creados por segundo
rate(demo_orders_created_total[5m])

LogQL (Loki)

# Todos los logs de la app
{service_name="monitoring-demo"}

# Solo errores
{service_name="monitoring-demo"} |= "ERROR"

# Logs con traceId específico
{service_name="monitoring-demo"} | json | traceId="abc123..."

# Tasa de errores en logs
sum(rate({service_name="monitoring-demo"} |= "ERROR" [5m]))

TraceQL (Tempo)

# Trazas del servicio de demostración
{resource.service.name="monitoring-demo"}

# Trazas lentas (más de 500ms)
{resource.service.name="monitoring-demo" && duration>500ms}

# Trazas con errores
{resource.service.name="monitoring-demo" && status=error}

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages