DataSkills Hub

Grafana Loki

Grafana Loki es el sistema open-source de agregación de logs para centralizar logs de servicios (Trino, Spark, Kafka, NiFi, Airflow, Ceph). Se integra con Grafana para búsqueda y visualización rápida. Los logs se envían vía Promtail (agente de recolección).

#Getting Started

#Conectarse a Loki

Acceso vía Grafana (recomendado)

<tu-url> → Data Sources → Loki

API REST de Loki (directo)

<tu-url>

Verificar estado

curl <tu-url>/ready
curl <tu-url>/loki/api/v1/status/buildinfo

#Componentes de Loki

Componente Rol Ubicación
Distributor Recibe logs vía push (Promtail) <tu-url>
Ingester Procesa y almacena logs en memoria Interno
Querier Lee logs de almacenamiento API /loki/api/v1/query
Promtail Agente recolector de logs En cada nodo

#Promtail — Recolección de Logs

#Archivos de configuración

Ruta estándar

/etc/promtail/config.yml

Ver logs de Promtail

docker logs promtail --tail 50
# o
journalctl -u promtail -n 50

#Estructura de config básica

clients:
  - url: <tu-url>/loki/api/v1/push

scrape_configs:
  - job_name: trino
    static_configs:
      - targets:
          - localhost
        labels:
          job: trino
          __path__: /var/log/trino/*.log

#Targets y labels en Promtail

Label Ejemplo Descripción
job trino Aplicación/servicio
host trino-worker-01 Nombre del nodo
environment production Entorno (prod, dev, staging)
level error Nivel del log (si extractable)

#LogQL — Lenguaje de Queries

#Queries básicas

Logs de un job específico

{job="trino"}

Logs de múltiples jobs

{job=~"trino|spark"}

Filtrar por host

{job="kafka", host="kafka-broker-01"}

#Búsqueda de texto

Logs que contienen palabra clave

{job="airflow"} |= "failed"

Logs que NO contienen palabra clave

{job="trino"} != "debug"

Coincidencia regex

{job="spark"} |~ "error.*timeout"

#Filtrado de logs (pipe operators)

{job="kafka"}
  |= "partition"           # Contiene
  != "rebalance"           # No contiene
  |~ "lag.*[0-9]{5,}"      # Regex: lag + 5+ dígitos

#Funciones de agregación en LogQL

Función Ejemplo Resultado
rate() rate({job="trino"}[5m]) Líneas/segundo
bytes_rate() bytes_rate({job="kafka"}[1m]) Bytes/segundo
count_over_time() count_over_time({job="airflow"}[1h]) Líneas en 1 hora
absent() absent(rate({job="ceph"}[5m])) Alerta si no hay logs

#Queries Prácticas

#Trino — Debugging de queries

Logs de una query fallida

{job="trino"} |= "FAILED" or "error"

Logs de queries lentas

{job="trino"} |~ "duration.*[0-9]{5,}"

Errores de memoria

{job="trino"} |= "OutOfMemory" or "memory exceeded"

#Spark — Monitoreo de jobs

Logs de jobs en ejecución

{job="spark"} |= "Running task" or "completed"

Fallos en executors

{job="spark"} |= "executor" and ("failed" or "lost")

Particiones y shuffle

{job="spark"} |~ "shuffle.*read.*[0-9]+ MB"

#Kafka — Consumer lag y rebalancing

Consumer lag detectado

{job="kafka"} |= "consumer lag" or "lagging"

Rebalancing de particiones

{job="kafka"} |~ "Rebalancing|RebalanceInProgress"

Errores en brokers

{job="kafka"} |= "broker" and ("fatal" or "error")

#Airflow — DAGs y Tasks

Task failures

{job="airflow"} |= "Task failed" or "Retrying"

DAG schedule y runs

{job="airflow"} |~ "SchedulerJob|DagRun.*state.*"

Errores de conexión

{job="airflow"} |= "Connection refused" or "timeout"

#Ceph — Health y OSDs

Estado del cluster

{job="ceph"} |= "health" or "HEALTH_WARN"

OSDs down

{job="ceph"} |= "down" or "Out of quorum"

Datos no replicados

{job="ceph"} |= "undersized" or "degraded"

#Análisis de Logs en Grafana

#Integración con Grafana

  1. Abrir Grafana: <tu-url>
  2. Ir a Explore
  3. Seleccionar Data Source: Loki
  4. Escribir query LogQL
  5. Ver logs y statistícas

#Alertas sobre logs

Crear alerta en Grafana si logs contienen error

count_over_time({job="trino"} |= "FAILED"[5m]) > 10

Alerta si no hay logs (servicio caído)

absent(rate({job="kafka"}[5m]))

#Parsing de logs y extracción de fields

Extraer duración de logs de Trino

{job="trino"} |~ "duration.*[0-9]+" | regexp "duration=(?P<duration>[0-9]+)"

Extraer status code de logs HTTP

{job="trino"} | regexp "status=(?P<status>\d+)"

#API REST de Loki

#Query instantánea

curl '<tu-url>/loki/api/v1/query' \
  --data-urlencode 'query={job="trino"}' \
  --data-urlencode 'time=1678953600'

#Range query (rango de tiempo)

curl '<tu-url>/loki/api/v1/query_range' \
  --data-urlencode 'query=rate({job="kafka"}[5m])' \
  --data-urlencode 'start=1678867200' \
  --data-urlencode 'end=1678953600' \
  --data-urlencode 'step=300'

#Labels y valores

# Listar todos los label names
curl '<tu-url>/loki/api/v1/labels'

# Valores de un label específico
curl '<tu-url>/loki/api/v1/label/job/values'

#Mejores Prácticas

#Nombrado de jobs y labels

Convención Ejemplo Descripción
Job = servicio job="trino" Nombre de la app/servicio
Host = nodo host="trino-worker-01" Nodo donde corre
Environment env="production" Entorno
Level level="error" Severidad del log

#Optimización de queries

Usar filtros explícitos (rápido)

{job="trino", host="trino-worker-01"}

Evitar búsquedas sin job (muy lento)

# MALO
{} |= "error"

# BIEN
{job="spark"} |= "error"

Limitar rango de tiempo en dashboards

  • Usar Last 1h, Last 6h en lugar de Last 7 days
  • Reduce carga en Loki

#Retención de logs

Logs se guardan ~3 días por defecto. Para cambiar:

# En /etc/loki/loki-config.yml
schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: s3
      schema: v11
      index:
        prefix: index_
        period: 24h

# Retención: 72 horas (3 días)
retention_deletes_enabled: true
retention_period: 72h

Recargar config

curl -X POST <tu-url>/loki/api/v1/reload

#Troubleshooting

#Logs no aparecen en Loki

  1. Verificar Promtail está corriendo:
ps aux | grep promtail
# o
docker ps | grep promtail
  1. Ver logs de Promtail:
docker logs promtail --tail 100
  1. Verificar conectividad a Loki:
curl <tu-url>/ready
  1. Revisar config de Promtail (paths, labels):
cat /etc/promtail/config.yml

#Query lenta o timeout

Problema: Query sin filtro job=

# LENTO
{} |= "error"

# RÁPIDO
{job="trino"} |= "error"

Solución: Siempre incluir job= como primer filtro.

#Loki fuera de memoria

Ver uso de memoria:

curl <tu-url>/metrics | grep memory

Reducir max_chunk_age en config (flush más frecuente a almacenamiento).