O logging centralizado é uma prática fundamental em ambientes DevOps, especialmente em arquiteturas de microsserviços e contêineres. Com a crescente complexidade dos sistemas, cada serviço gera seus próprios logs, o que torna a depuração e o monitoramento extremamente difíceis se não houver uma forma de agregar e correlacionar essas informações. Nesta aula, vamos explorar o conceito de logging centralizado, desde a estruturação dos logs até a implementação de pipelines de agregação e políticas de retenção, passando por ferramentas populares como ELK Stack e Loki.

Vamos começar entendendo por que logs estruturados são essenciais para a centralização, depois mergulharemos nas ferramentas de agregação, discutiremos estratégias de retenção e finalizaremos com boas práticas que você pode adotar imediatamente em seus projetos.

Logs estruturados

Logs estruturados são registros de eventos que seguem um formato predefinido, como JSON, em vez de texto livre. Isso permite que ferramentas de agregação e análise façam parsing automático e extraiam campos específicos, como timestamp, nível de severidade, nome do serviço, ID de correlação, entre outros. Em contraste, logs não estruturados são difíceis de filtrar e correlacionar, exigindo expressões regulares complexas e muitas vezes falhas.

Por exemplo, um log tradicional em texto livre pode ser:

2025-01-27 10:15:30 ERROR Failed to connect to database

Um log estruturado equivalente em JSON seria:

{ "timestamp": "2025-01-27T10:15:30Z", "level": "ERROR", "message": "Failed to connect to database", "service": "user-service", "db": "postgres" }

Com logs estruturados, você pode facilmente consultar todos os erros de um serviço específico, ou todos os logs que mencionam um determinado banco de dados, sem precisar de parsing manual. Ferramentas como Elasticsearch e Loki indexam esses campos automaticamente, permitindo buscas rápidas e eficientes.

Para gerar logs estruturados, você pode usar bibliotecas de logging em sua linguagem de programação que suportam formatação JSON, como python-json-logger para Python, logrus para Go, ou pino para Node.js. Em bash, você pode usar ferramentas como jq para construir JSON a partir de comandos.

Exemplo de geração de log estruturado em bash usando jq:

#!/bin/bash
log() {
  local level="$1"
  local message="$2"
  echo "$(jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg lvl "$level" --arg msg "$message" --arg svc "my-service" '{timestamp: $ts, level: $lvl, message: $msg, service: $svc}')"
}
log "INFO" "Service started"
log "ERROR" "Database connection failed"

Agregação (ELK, Loki - visão geral)

A agregação de logs envolve coletar logs de todas as fontes (servidores, contêineres, aplicações) e centralizá-los em um único local para busca, análise e alertas. Duas das stacks mais populares são o ELK Stack (Elasticsearch, Logstash, Kibana) e o Grafana Loki. Vamos entender cada uma.

ELK Stack é composto por:

  • Elasticsearch: um mecanismo de busca e análise baseado em Lucene, que armazena e indexa os logs.
  • Logstash: uma ferramenta de ingestão de dados que coleta logs de múltiplas fontes, transforma e envia para o Elasticsearch.
  • Kibana: uma interface web para visualizar e consultar os dados no Elasticsearch.

O fluxo típico é: aplicações enviam logs (via Filebeat ou diretamente) para o Logstash, que os processa e envia para o Elasticsearch, onde são indexados. O Kibana permite criar dashboards e consultas. O ELK é poderoso, mas pode ser pesado em termos de recursos, exigindo configuração e manutenção.

Grafana Loki é uma alternativa mais leve, projetada especificamente para logs, inspirada no Prometheus. Ele usa um armazenamento baseado em objetos e indexa apenas os metadados (labels), não o conteúdo completo, o que o torna mais eficiente em custo. O Loki é frequentemente usado com o Grafana para visualização e com o Promtail para coleta de logs.

Exemplo de configuração do Loki para receber logs de um arquivo usando Promtail:

# promtail.yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0
positions:
  filename: /tmp/positions.yaml
clients:
  - url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
  static_configs:
  - targets:
      - localhost
    labels:
      job: varlogs
      __path__: /var/log/*.log

Ambas as ferramentas têm seus prós e contras. O ELK oferece recursos avançados de busca e análise, mas é mais complexo. O Loki é mais simples e integra-se bem com o Grafana, mas tem limitações em consultas complexas. A escolha depende do seu contexto e necessidades.

Retenção

Políticas de retenção definem por quanto tempo os logs devem ser armazenados. Isso é crucial por vários motivos: conformidade com regulamentações (como GDPR ou LGPD), custos de armazenamento, e necessidade de dados históricos para auditoria e análise de tendências. Uma boa política de retenção equilibra a necessidade de dados com os custos.

Em ambientes de produção, é comum definir retenção por níveis: logs quentes (hot) para os últimos dias, logs mornos (warm) para semanas, e logs frios (cold) para meses ou anos, usando diferentes tipos de armazenamento. Ferramentas como Elasticsearch oferecem índices com políticas de ciclo de vida (ILM) que automatizam essa transição.

Exemplo de política de retenção no Elasticsearch usando ILM:

# Criar política ILM
PUT _ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "7d"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

No Loki, a retenção é configurada no arquivo de configuração, definindo o período de retenção por tenant ou globalmente:

# loki.yaml
limits_config:
  retention_period: 720h  # 30 dias
chunk_store_config:
  max_look_back_period: 720h
schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

É importante monitorar o uso de armazenamento e ajustar as políticas conforme necessário. Lembre-se de que logs são dados valiosos, mas também podem se tornar um passivo se não forem gerenciados adequadamente.

Boas práticas

Adotar boas práticas de logging centralizado pode evitar muitos problemas. Aqui estão algumas recomendações:

  • Use logs estruturados: como vimos, isso facilita a análise automática.
  • Inclua IDs de correlação: para rastrear uma requisição através de múltiplos serviços, adicione um ID único (como request_id) a todos os logs daquela requisição.
  • Defina níveis de log claros: use DEBUG, INFO, WARN, ERROR de forma consistente e evite logs excessivos em produção.
  • Centralize desde o início: não espere o sistema crescer para implementar logging centralizado; comece em projetos pequenos.
  • Monitore o pipeline de logs: garanta que os logs estão chegando ao destino e que não há gargalos ou perdas.
  • Proteja os logs: logs podem conter dados sensíveis; use criptografia em trânsito e em repouso, e controle o acesso.
  • Automatize a configuração: use ferramentas de IaC (Infraestrutura como Código) para gerenciar a configuração do stack de logs.

Além disso, é importante testar a pipeline de logs regularmente, simulando falhas e verificando se os logs são coletados corretamente. Documente os formatos e políticas para que a equipe esteja alinhada.

Referências

Exercícios

  1. Exercício 1: Crie um script em bash que gere logs estruturados em JSON para um serviço fictício. O script deve ter uma função log que aceita nível e mensagem, e deve incluir timestamp, serviço e nível. Teste com pelo menos 3 mensagens de níveis diferentes.

✓ Resposta:
#!/bin/bash
log() {
  local level="$1"
  local message="$2"
  echo "$(jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg lvl "$level" --arg msg "$message" --arg svc "my-service" '{timestamp: $ts, level: $lvl, message: $msg, service: $svc}')"
}
log "INFO" "Service started"
log "WARN" "Memory usage high"
log "ERROR" "Failed to connect to database"
  • Exercício 2: Explique a diferença entre ELK Stack e Loki em termos de arquitetura e casos de uso. Forneça um exemplo de cenário onde você escolheria um em vez do outro.
  • ✓ Resposta: O ELK Stack é mais robusto, com indexação completa e busca avançada, ideal para análises complexas e grandes volumes. Loki é mais leve, indexa apenas labels, e é mais econômico, integrando-se bem com Grafana e Kubernetes. Por exemplo, em um ambiente com muitos microsserviços e necessidade de correlação rápida, Loki pode ser suficiente. Em um cenário com necessidade de consultas complexas e agregações, ELK é melhor.
  • Exercício 3: Configure uma política de retenção no Loki para manter logs por 7 dias. Escreva o trecho de configuração necessário.
  • ✓ Resposta:
    limits_config:
      retention_period: 168h  # 7 dias
    chunk_store_config:
      max_look_back_period: 168h
    schema_config:
      configs:
        - from: 2020-10-24
          store: boltdb-shipper
          object_store: filesystem
          schema: v11
          index:
            prefix: index_
            period: 24h
  • Exercício 4: Liste 3 boas práticas de logging centralizado e explique por que cada uma é importante.
  • ✓ Resposta: 1. Usar logs estruturados para facilitar a busca e análise automática. 2. Incluir IDs de correlação para rastrear requisições entre serviços. 3. Definir níveis de log para evitar excesso e facilitar a filtragem. 4. Monitorar o pipeline para garantir que os logs não se percam.
  • Exercício 5: Dado o seguinte log não estruturado: "2025-01-27 10:15:30 ERROR Failed to connect to database". Transforme-o em um log estruturado no formato JSON, adicionando campos como serviço e nível.
  • ✓ Resposta:
    { "timestamp": "2025-01-27T10:15:30Z", "level": "ERROR", "message": "Failed to connect to database", "service": "unknown" }

    Observações finais

    O logging centralizado é um pilar da observabilidade em DevOps. Dominar logs estruturados, ferramentas de agregação e políticas de retenção permite que você mantenha sistemas saudáveis e diagnosticáveis. Lembre-se de que a implementação deve ser iterativa: comece simples, monitore, e evolua conforme a necessidade. Pratique com as ferramentas em ambientes de teste e sempre mantenha a segurança dos dados em mente.