Estratégias de logging: o que e como registrar

1. Fundamentos do Logging Eficaz

Em sistemas distribuídos modernos, o log é frequentemente a única fonte de verdade quando algo dá errado. Diferente de métricas (que mostram agregados) ou tracing (que mostra o caminho de uma requisição), o logging fornece o contexto narrativo do que realmente aconteceu em cada ponto da execução.

Existem três categorias principais de logging:

  • Logging operacional: usado para monitorar a saúde do sistema (startups, shutdowns, heartbeats)
  • Logging de auditoria: registro imutável de ações críticas para compliance (quem fez o quê e quando)
  • Logging de depuração: detalhes granulares usados durante desenvolvimento e troubleshooting

O princípio fundamental é: registrar informação suficiente para diagnosticar problemas, mas não tanta a ponto de gerar ruído ou custo excessivo de armazenamento e processamento.

2. O que registrar: categorias essenciais de eventos

Nem todo evento merece um log. As categorias que sempre devem ser registradas são:

Eventos de entrada e saída — toda requisição recebida e sua respectiva resposta devem ser logadas com um identificador de correlação único:

2025-01-15T10:30:00.123Z INFO [user-service] Request iniciada | trace_id=abc123 | method=POST | path=/api/users | body_size=2048
2025-01-15T10:30:00.456Z INFO [user-service] Request concluída | trace_id=abc123 | status=201 | duration_ms=333

Mudanças de estado críticas — transições de estado, falhas de conexão, timeouts, abertura de circuit breakers:

2025-01-15T10:30:01.789Z WARN [payment-service] Circuit breaker aberto | serviço=gateway-pagamento | timeout_ms=5000 | tentativas=3

Dados de contexto — ID de usuário, ID de transação, serviço de origem, versão do deploy. Esses campos permitem filtrar e correlacionar logs entre serviços:

2025-01-15T10:30:02.000Z ERROR [order-service] Falha ao processar pedido | user_id=u789 | transaction_id=txn456 | service_version=2.1.0 | erro=estoque_insuficiente

3. O que NÃO registrar: riscos e armadilhas comuns

Dados sensíveis — senhas, tokens de autenticação, números de cartão de crédito, PII (informações pessoais identificáveis). Se precisar registrar algo sensível, use mascaramento:

# ERRADO
2025-01-15T10:30:03.000Z INFO Login realizado | email=joao@email.com | senha=minhaSenha123

# CORRETO
2025-01-15T10:30:03.000Z INFO Login realizado | email=j***@email.com | senha=***

Logs excessivos em hot paths — loops que executam milhares de vezes por segundo não devem logar cada iteração. Isso gera overhead de I/O e degrada performance. Use contadores ou amostragem.

Informações redundantes — se você já tem métricas para latência (p99, p50) e tracing para o caminho completo da requisição, não precisa logar cada etapa intermediária. Log só o que métricas e tracing não capturam.

4. Níveis de severidade e quando usar cada um

Nível Uso Exemplo
DEBUG Desenvolvimento e troubleshooting local. Desligado em produção. DEBUG Parâmetros da query: {filtros}
INFO Fluxo normal de operação. Startup, shutdown, requests bem-sucedidos. INFO Serviço iniciado na porta 8080
WARN Situações anômalas que não quebram o sistema. Retry, degradação leve. WARN Timeout na primeira tentativa, iniciando retry
ERROR Falhas que exigem intervenção. Exceções não tratadas, dependências offline. ERROR Banco de dados indisponível após 3 tentativas
FATAL Estado irrecuperável que encerra o processo. FATAL Falha na inicialização do pool de conexões

Regra prática: em produção, configure o nível mínimo como INFO ou WARN. Ative DEBUG apenas sob demanda para troubleshooting específico.

5. Estrutura e formato do registro

Logging estruturado em JSON é o padrão da indústria. Ele permite consultas eficientes em sistemas centralizados como Elasticsearch, Splunk ou Loki:

{
  "timestamp": "2025-01-15T10:30:04.000Z",
  "level": "ERROR",
  "service": "api-gateway",
  "message": "Falha ao rotear requisição",
  "trace_id": "abc123",
  "span_id": "def456",
  "environment": "production",
  "host": "web-01",
  "method": "GET",
  "path": "/api/users/789",
  "status_code": 502,
  "duration_ms": 15000,
  "error": "upstream_connection_timeout"
}

Campos obrigatórios em todo log:
- timestamp — formato ISO 8601 com timezone
- level — DEBUG, INFO, WARN, ERROR, FATAL
- service — nome do serviço que gerou o log
- message — mensagem legível do evento
- trace_id — ID de correlação entre serviços

6. Estratégias de contexto e correlação

Em sistemas distribuídos, um único trace_id deve ser propagado entre todos os serviços envolvidos em uma requisição. Isso permite reconstruir o fluxo completo.

Propagação síncrona — o trace_id viaja no header HTTP (X-Trace-Id) e é extraído no middleware de cada serviço:

# Serviço A recebe requisição sem trace_id, gera um novo
trace_id = gerar_uuid()

# Serviço A chama Serviço B, passa trace_id no header
GET /api/orders HTTP/1.1
X-Trace-Id: abc123

# Serviço B extrai trace_id do header e usa em todos os logs
2025-01-15T10:30:05.000Z INFO [order-service] Processando pedido | trace_id=abc123

Propagação assíncrona — em filas ou mensageria, o trace_id deve ser incluído no payload ou nos headers da mensagem.

MDC (Mapped Diagnostic Context) — em Java, .NET e outras linguagens, use MDC para anexar automaticamente o contexto (trace_id, user_id) a todos os logs gerados durante a execução de uma thread ou request scope:

// Configuração do MDC no middleware
MDC.put("trace_id", request.getHeader("X-Trace-Id"));
MDC.put("user_id", usuario.getId());

// Todos os logs subsequentes incluirão esses campos automaticamente
logger.info("Pedido criado com sucesso");
// Saída: 2025-01-15T10:30:06.000Z INFO trace_id=abc123 user_id=u789 Pedido criado com sucesso

7. Gerenciamento de volume e rotação

Logs sem controle viram custo e ruído. Políticas recomendadas:

  • Retenção: logs de INFO e WARN — 30 dias. Logs de ERROR e FATAL — 90 dias (ou conforme compliance). Logs de auditoria — 1 ano ou mais.
  • Amostragem seletiva: para logs de alta frequência (ex: health checks a cada 5 segundos), registre apenas 1 a cada 10 ocorrências ou apenas quando falharem.
  • Buffers e envio assíncrono: nunca bloqueie a thread da aplicação esperando o log ser escrito em disco ou enviado para a rede. Use bibliotecas que operam em background (ex: Logback AsyncAppender, Serilog sink assíncrono).

8. Monitoramento e alertas baseados em logs

Dashboards e alertas transformam logs de repositório morto em ferramenta proativa:

Dashboards essenciais:
- Taxa de erros por serviço e endpoint (quantidade de ERROR por minuto)
- Distribuição de níveis de severidade ao longo do tempo
- Top 5 mensagens de erro mais frequentes
- Latência média e p99 extraída de logs de resposta

Alertas críticos:
- Pico de ERROR (ex: > 10 erros/minuto em qualquer serviço)
- Ausência de heartbeat (nenhum log de INFO de um serviço por > 5 minutos)
- Padrões anômalos (ex: aumento súbito de WARN de timeouts)

Revisão periódica: a cada sprint, revise os logs registrados. Ajuste níveis que estão muito verbosos e remova logs que se provaram inúteis. Logging é um produto que precisa de manutenção contínua.


Referências