Logs centralizados com Grafana Loki

Loki é o sistema de armazenamento de logs da Grafana Labs, armazena logs sem indexação de conteúdo (apenas labels), tornando-o muito mais barato que Elasticsearch para o mesmo volume. Integrado ao Grafana, você correlaciona logs com métricas no mesmo painel, sem trocar de ferramenta.

docker-compose.yml: Loki + Promtail

Adicione Loki e Promtail ao stack de monitoramento existente:

yaml
services:
  loki:
    image: grafana/loki:latest
    restart: always
    volumes:
      - ./loki/config.yml:/etc/loki/config.yml:ro
      - loki_data:/loki
    command: -config.file=/etc/loki/config.yml
    ports:
      - "127.0.0.1:3100:3100"
    networks:
      - monitoring

  promtail:
    image: grafana/promtail:latest
    restart: always
    volumes:
      - ./promtail/config.yml:/etc/promtail/config.yml:ro
      - /var/log:/var/log:ro           # logs do sistema host
      - /var/lib/docker/containers:/var/lib/docker/containers:ro  # logs Docker
    command: -config.file=/etc/promtail/config.yml
    networks:
      - monitoring

volumes:
  loki_data:

Configuração do Loki

Configuração mínima para produção com retenção de 30 dias:

yaml
# loki/config.yml
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

query_range:
  results_cache:
    cache:
      embedded_cache:
        enabled: true
        max_size_mb: 100

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  retention_period: 30d    # manter logs por 30 dias

compactor:
  working_directory: /loki/compactor
  retention_enabled: true

Configuração do Promtail

Promtail coleta logs de containers Docker e arquivos do sistema:

yaml
# promtail/config.yml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml    # estado de leitura dos logs

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  # Logs de containers Docker
  - job_name: docker
    static_configs:
      - targets:
          - localhost
        labels:
          job: docker
          __path__: /var/lib/docker/containers/*/*.log
    pipeline_stages:
      - json:
          expressions:
            stream: stream
            log: log
      - labels:
          stream:
      - output:
          source: log

  # Logs do sistema (syslog, auth, etc.)
  - job_name: syslog
    static_configs:
      - targets:
          - localhost
        labels:
          job: syslog
          host: vps-prod-01
          __path__: /var/log/{syslog,auth.log,kern.log}

Adicionar Loki como datasource no Grafana

Configure Loki como fonte de dados e explore logs no Grafana:

bash
# Adicionar datasource Loki via API
curl -X POST http://localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -u admin:senha \
  -d '{
    "name": "Loki",
    "type": "loki",
    "url": "http://loki:3100",
    "access": "proxy"
  }'

# Queries LogQL básicas (aba Explore no Grafana):

# Ver todos os logs de um container
{job="docker", container="minha_api"}

# Filtrar por nível de log
{job="docker"} |= "ERROR"

# Regex para padrões específicos
{job="docker"} |~ "exception|traceback|fatal"

# Contar erros por minuto (metric query)
sum(rate({job="docker"} |= "ERROR" [1m])) by (container)

# Ver logs de SSH do sistema
{job="syslog", filename="/var/log/auth.log"} |= "Invalid user"

Driver de log Docker para Loki

Alternativa ao Promtail: configure o Docker para enviar logs diretamente ao Loki:

bash
# Instalar plugin Loki para Docker
docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions

# Verificar instalação
docker plugin ls | grep loki

# Configurar como driver padrão: /etc/docker/daemon.json
{
  "log-driver": "loki",
  "log-opts": {
    "loki-url": "http://localhost:3100/loki/api/v1/push",
    "loki-batch-size": "400",
    "loki-external-labels": "host=vps-prod-01,env=production"
  }
}

# Ou por container no docker-compose.yml:
services:
  app:
    logging:
      driver: loki
      options:
        loki-url: "http://loki:3100/loki/api/v1/push"
        loki-external-labels: "service=minha-api,env=production"

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Elasticsearch indexa o conteúdo completo dos logs (caro em CPU e RAM, mas busca muito rápida em texto livre). Loki indexa apenas labels (CPU/RAM muito menor, busca por conteúdo mais lenta). Para VPS: Loki é 5-10x mais econômico em recursos. Para compliance/segurança que requer full-text search em logs históricos: Elasticsearch.

Loki comprime logs com Snappy (ratio ~5-10x). 1 GB de logs brutos → ~100-200 MB armazenados. Para uma VPS com 3-5 containers gerando ~100 MB/dia de logs: 30 dias = ~600 MB comprimidos. Monitore com: du -sh /var/lib/docker/volumes/*/loki.

Grafana 9+ tem Explore Correlation nativa. Em um painel: adicione links entre gráficos de métricas e queries LogQL correspondentes. Por exemplo: do gráfico de erros HTTP → click abre Loki filtrado por {service="minha-api"} |= "error" no mesmo período de tempo.

docker compose logs promtail, verifica erros de configuração. curl http://localhost:9080/ready, verifica se está rodando. curl http://localhost:9080/metrics | grep promtail_file_bytes_total, verifica se está lendo arquivos. O positions.yaml em /tmp/ registra a posição de leitura de cada arquivo, delete para re-processar desde o início.

Sim desde Grafana 9. Use LogQL metric queries: sum(count_over_time({job="docker"} |= "ERROR" [5m])). Configure alerta se > threshold. Exemplo: alertar quando mais de 10 erros em 5 minutos em qualquer container.