Saltar a contenido

Grafana

Grafana visualiza métricas, logs y trazas de la plataforma en dashboards unificados. Integra Prometheus (métricas), Loki (logs) y Tempo (trazas) en una sola interfaz, permitiendo correlacionar datos de observabilidad para diagnóstico rápido.

Instalación con Docker Compose

# compose.observability.yml
services:
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
      GF_USERS_ALLOW_SIGN_UP: "false"
      GF_SERVER_ROOT_URL: https://monitoring.example.com
      GF_AUTH_ANONYMOUS_ENABLED: "false"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    networks:
      - frontend

volumes:
  grafana_data:

Configurar datasources (provisioning)

# grafana/provisioning/datasources/datasources.yml
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    url: http://prometheus:9090
    access: proxy
    isDefault: true
    jsonData:
      timeInterval: "15s"

  - name: Loki
    type: loki
    url: http://loki:3100
    access: proxy
    jsonData:
      derivedFields:
        - datasourceUid: tempo
          matcherRegex: '"traceId":"(\w+)"'
          name: TraceID
          url: '$${__value.raw}'

  - name: Tempo
    type: tempo
    url: http://tempo:3200
    access: proxy
    jsonData:
      tracesToLogs:
        datasourceUid: loki
        filterByTraceID: true
        spanStartTimeShift: -1h
        spanEndTimeShift: 1h

Dashboard de Keycloak

Importar el dashboard community de Keycloak (ID: 19659 en grafana.com) o crear uno personalizado:

Panels recomendados

Panel 1 — Tasa de logins por realm
  Query: rate(keycloak_logins_total[5m])
  Tipo: Time series
  Leyenda: {{realm}}

Panel 2 — Errores de login
  Query: rate(keycloak_login_errors_total[5m])
  Tipo: Time series, color rojo
  Alerta: > 0.1 req/s durante 5 min

Panel 3 — Sesiones activas
  Query: keycloak_sessions_active_total
  Tipo: Stat (número actual)

Panel 4 — Uso de memoria JVM de Keycloak
  Query: jvm_memory_used_bytes{job="keycloak", area="heap"}
         / jvm_memory_max_bytes{job="keycloak", area="heap"} * 100
  Tipo: Gauge (0-100%)
  Umbral rojo: > 85%

Panel 5 — Top clientes por tokens emitidos
  Query: topk(5, sum by (clientId) (rate(keycloak_client_logins_total[1h])))
  Tipo: Bar chart

Importar dashboard via API

# Descargar dashboard de Keycloak de la comunidad
curl -s https://grafana.com/api/dashboards/19659/revisions/latest/download > keycloak-dashboard.json

# Importar via API de Grafana
curl -s -X POST \
  -H "Content-Type: application/json" \
  -u "admin:${GRAFANA_PASSWORD}" \
  -d "{\"dashboard\": $(cat keycloak-dashboard.json), \"overwrite\": true}" \
  http://localhost:3000/api/dashboards/import

Dashboard de Spring WebFlux APIs

Panel 1 — Latencia p95 por endpoint
  Query: histogram_quantile(0.95, rate(http_server_requests_seconds_bucket{job="identity-api"}[5m]))
  Tipo: Time series

Panel 2 — Tasa de errores HTTP 5xx
  Query: rate(http_server_requests_seconds_count{status=~"5..",job="identity-api"}[5m])
  Tipo: Time series, color naranja

Panel 3 — Throughput (req/s)
  Query: rate(http_server_requests_seconds_count{job="identity-api"}[1m])
  Tipo: Stat

Panel 4 — CPU del proceso
  Query: process_cpu_usage{job="identity-api"}
  Tipo: Gauge

Logs con Loki

# En el panel de Logs, query LogQL:

# Todos los errores de Keycloak
{container="keycloak"} |= "ERROR"

# Errores de login por realm
{container="keycloak"} | json | level="ERROR" | line_format "{{.message}}"

# Logs de Spring con traceId específico
{container="identity-api"} |= "traceId=abc123"

# Correlacionar con Tempo: hacer clic en el traceId en el log
# abre automáticamente la traza en Tempo

Alertas en Grafana

# grafana/provisioning/alerting/alerts.yml
apiVersion: 1

groups:
  - name: Identity Platform
    interval: 1m
    rules:
      - uid: keycloak-down
        title: Keycloak no disponible
        condition: C
        data:
          - refId: A
            queryType: ''
            relativeTimeRange:
              from: 600
              to: 0
            datasourceUid: prometheus
            model:
              expr: up{job="keycloak"}
              intervalMs: 1000
              maxDataPoints: 43200
              refId: A
        noDataState: Alerting
        execErrState: Alerting
        for: 1m
        annotations:
          summary: "Keycloak no está respondiendo"
        labels:
          severity: critical

Explorar trazas desde logs

Configura el datasource de Loki con derivedFields para que los traceId en los logs sean links clicables que abren la traza en Tempo. Esto reduce el tiempo de diagnóstico de minutos a segundos.