Loki + Grafana: logs centralizados na VPS

Grafana Loki é o "Prometheus para logs", armazena apenas os metadados (labels) dos logs com índices, mantendo o texto bruto comprimido em storage. É 10× mais econômico que o Elasticsearch para a maioria dos casos de uso. Integrado ao Grafana que você já tem, centraliza logs de todos os containers e serviços em um único painel.

Instalar Loki com Docker Compose

Stack completa com Loki, Promtail e Grafana:

yaml
# docker-compose.yml
services:
  loki:
    image: grafana/loki:latest
    restart: always
    ports:
      - "127.0.0.1:3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - loki_data:/loki
      - ./loki-config.yaml:/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    restart: always
    volumes:
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - ./promtail-config.yaml:/etc/promtail/config.yaml
    command: -config.file=/etc/promtail/config.yaml

  grafana:
    image: grafana/grafana:latest
    restart: always
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
    volumes:
      - grafana_data:/var/lib/grafana

volumes:
  loki_data:
  grafana_data:

Configurar Promtail para coletar logs

promtail-config.yaml para ler logs do Docker e do sistema:

yaml
# promtail-config.yaml
server:
  http_listen_port: 9080

positions:
  filename: /tmp/positions.yaml

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

scrape_configs:
  # Logs de containers Docker:
  - job_name: docker
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: ['__meta_docker_container_name']
        target_label: container
      - source_labels: ['__meta_docker_container_log_stream']
        target_label: stream
      - source_labels: ['__meta_docker_compose_service']
        target_label: service

  # Logs do Nginx:
  - job_name: nginx
    static_configs:
      - targets: [localhost]
        labels:
          job: nginx
          __path__: /var/log/nginx/*.log

  # Logs do sistema (auth, syslog):
  - job_name: system
    static_configs:
      - targets: [localhost]
        labels:
          job: system
          __path__: /var/log/{auth,syslog}.log

Queries LogQL no Grafana

Pesquisar e filtrar logs com a linguagem LogQL:

bash
# LogQL — sintaxe similar ao PromQL

# Todos os logs de um container:
{container="minha-api-app-1"}

# Filtrar por texto (grep):
{container="minha-api-app-1"} |= "ERROR"

# Excluir linha:
{job="nginx"} != "health"

# Parsear JSON estruturado e filtrar por campo:
{container="minha-api"} | json | level="error"

# Parsear log do Nginx (logfmt):
{job="nginx"} | logfmt | status >= 500

# Contar erros por minuto (métrica a partir de log):
rate({container="minha-api"} |= "ERROR" [1m])

# Top 10 IPs com mais erros 500:
topk(10,
  sum by (remote_addr) (
    rate({job="nginx"} | logfmt | status=~"5.." [5m])
  )
)

# No Grafana — Explore → Loki → inserir query LogQL
# Ou criar dashboard com painéis de log

Configurar alertas baseados em logs

Alertar quando padrão de erro aparece nos logs:

yaml
# No Grafana — Alerting → Alert Rules → New rule
# Usar Loki como data source

# Exemplo: alertar quando > 10 erros 500 em 5 min:
# Query:
sum(rate({job="nginx"} | logfmt | status=~"5.." [5m])) > 0.033

# Ou via arquivo de regras do Loki (ruler):
# loki-config.yaml — adicionar:
ruler:
  storage:
    type: local
    local:
      directory: /loki/rules
  rule_path: /loki/rules
  alertmanager_url: http://alertmanager:9093

# /loki/rules/default/rules.yaml:
groups:
  - name: api-errors
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate({container="minha-api"} |= "ERROR" [5m])) > 1
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Taxa de erros alta na API"

Enviar logs da aplicação diretamente ao Loki

Integrar Node.js com Loki via Pino ou Winston:

typescript
// npm install pino pino-loki

import pino from 'pino'

const logger = pino({
  transport: {
    targets: [
      // Console (desenvolvimento):
      { target: 'pino-pretty', level: 'debug', options: {} },
      // Loki (produção):
      {
        target: 'pino-loki',
        level: 'info',
        options: {
          host: 'http://localhost:3100',
          labels: {
            app: 'minha-api',
            env: process.env.NODE_ENV,
          },
          // Enriquecer com campos do log como labels:
          propsToLabels: ['level', 'service'],
          // Intervalo de envio em batch (ms):
          interval: 5,
        },
      },
    ],
  },
})

// Usar o logger na aplicação:
logger.info({ userId: '123', route: '/api/pedidos' }, 'Pedido criado')
logger.error({ err: error, userId: '123' }, 'Falha ao processar pedido')

// Os logs aparecem automaticamente no Grafana Explore → Loki

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

Loki: indexa apenas as labels (não o conteúdo), usa muito menos RAM e disco, ideal para logs de containers onde você busca por serviço/nível/container. Elasticsearch: indexa o conteúdo completo, buscas full-text poderosas, mas consome 4-8 GB de RAM apenas para rodar. Para a maioria das VPS e equipes pequenas: Loki é suficiente e muito mais econômico.

Promtail: feito especificamente para Loki, configuração simples, descoberta automática de containers Docker. Filebeat: melhor integração com Elasticsearch, mais configurações. Fluentd: mais poderoso para transformações complexas, mas configuração mais verbosa. Para Loki: use Promtail. Para Elasticsearch: Filebeat. Para pipelines complexos: Fluentd ou Vector.

Loki é extremamente eficiente, uma VPS de 4 GB RAM com SSD de 100 GB suporta facilmente 10-50 GB de logs por dia com retenção de 30 dias. O segredo é a compressão: logs de texto comprimem 10-20×. Configure retention_period: 720h (30 dias) no loki-config.yaml para controlar uso de disco.

Zero mudança na aplicação, o Promtail lê diretamente os arquivos de log do Docker em /var/lib/docker/containers. Qualquer coisa que o container escreve em stdout/stderr aparece automaticamente no Loki com labels do container. Para logs estruturados (JSON): adicione | json na query LogQL para parsear os campos.

Sim, Grafana Loki é open-source (Apache 2.0). O Grafana Cloud oferece uma versão gerenciada com plano gratuito (50 GB/mês). Self-hosted: gratuito sem limites além do hardware. O stack completo (Loki + Grafana + Prometheus) é 100% gratuito para self-hosting.