- Nos sistemas distribuídos modernos, as abordagens tradicionais de logging têm limitações estruturais que impedem transmitir a verdade
- Os logs ainda são projetados com base no ambiente de servidor único de 2005, então perdem o contexto de requisições que passam por múltiplos serviços, bancos de dados e caches
- A simples busca por strings não entende estrutura, relações e correlação, dificultando encontrar a causa do problema
- A solução é registrar, para cada requisição, um único “Wide Event” (ou “Canonical Log Line”) contendo todo o contexto
- Com isso, os logs deixam de ser apenas texto e se tornam um ativo de dados analisável
O problema fundamental do logging
- Os logs tradicionais foram criados assumindo a era dos servidores monolíticos e não refletem a arquitetura moderna de serviços distribuídos
- Uma única requisição passa por vários serviços, DBs, caches e filas, mas os logs ainda são registrados como se estivessem em um único servidor
- No exemplo de log, são geradas 13 linhas por requisição; com 10.000 usuários simultâneos, isso vira 130.000 linhas por segundo, mas a maior parte é informação sem utilidade
- Quando ocorre um problema, o que se precisa é de contexto, mas os logs atuais carecem dele
Os limites da busca por strings
- Quando um usuário relata “o pagamento não funciona”, mesmo procurando os logs por e-mail ou
user_id, é difícil obter resultados úteis porque não há estrutura consistente
- O mesmo ID de usuário pode ser registrado de dezenas de formas diferentes, como
user-123, user_id=user-123, {"userId":"user-123"} etc.
- Como o formato dos logs varia entre os serviços, é impossível rastrear eventos relacionados
- O problema central é que os logs foram projetados com foco na escrita (write) e não estão otimizados para consulta (query)
Definição dos conceitos centrais
- Structured Logging: forma de registrar em pares chave-valor (JSON) em vez de strings
- Cardinality (cardinalidade): número de valores únicos de um campo; por exemplo,
user_id é muito alto
- Dimensionality (dimensionalidade): número de campos em um evento de log; quanto maior, maior a possibilidade de análise
- Wide Event / Canonical Log Line: um único evento de log por requisição, rico em contexto
- A maioria dos sistemas de logging limita dados de alta cardinalidade por questões de custo, mas, na prática, são justamente esses os mais úteis para debugging
Os limites do OpenTelemetry
- OpenTelemetry (OTel) é um conjunto de protocolos e SDKs que fornece apenas o padrão para coleta e transmissão de dados
- Porém, o OTel não faz o seguinte
- Não decide o que deve ser registrado
- Não adiciona automaticamente contexto de negócio (por exemplo, nível de assinatura, valor do carrinho etc.)
- Não muda a forma de pensar sobre logging dos desenvolvedores
- Mesmo usando a mesma biblioteca, a experiência de debugging difere radicalmente entre uma instrumentação que adiciona contexto de forma intencional e uma instrumentação simples
- O OTel é apenas a infraestrutura de transporte (plumbing); o que será enviado continua sendo uma decisão do desenvolvedor
A abordagem Wide Event / Canonical Log Line
- É preciso abandonar o logging centrado em “o que o código está fazendo” e passar a registrar “o que aconteceu com a requisição”
- Para cada requisição, gera-se um único evento amplo por serviço
- Ele pode incluir mais de 50 campos, como requisição, usuário, pagamento, erro e ambiente
- O JSON de exemplo inclui
user_id, subscription_tier, service_version, error_code e todo o contexto necessário para debugging
- Com isso, uma única busca já permite análises imediatas, como descobrir “a causa da falha de pagamento de usuários premium”
Uso de queries com Wide Event
- Wide Event não é tratado com simples busca textual, mas com consultas em dados estruturados
- Com dados de alta cardinalidade e alta dimensionalidade, torna-se possível fazer debugging em nível de análise em tempo real
- Ex.: é possível executar imediatamente uma consulta como “agregar a taxa de falha de pagamento de usuários premium na última hora por código de erro”
Padrão de implementação
- O evento é montado ao longo de todo o ciclo de vida da requisição e emitido apenas uma vez no final
- No middleware, inicializam-se campos básicos como
request_id, timestamp, method, path
- No handler, adicionam-se gradualmente informações de usuário, carrinho, pagamento e erro
- Ao final, registra-se um único evento JSON com
logger.info(event)
Controle de custo com sampling
- Como registrar mais de 50 campos por requisição faz o custo disparar, é necessário usar sampling
- O sampling aleatório simples pode deixar erros passarem despercebidos
- É proposta uma estratégia de Tail Sampling
- Erros (como 500) são sempre armazenados
- Requisições lentas (p99 ou acima) são sempre armazenadas
- Usuários VIP e sessões com flags específicas são sempre armazenados
- O restante é amostrado aleatoriamente em apenas 1–5%
- Assim, é possível reduzir custos e preservar os eventos mais importantes ao mesmo tempo
Equívocos comuns
- Structured Logging ≠ Wide Event: ter formato JSON por si só não basta; o contexto é o essencial
- Usar OpenTelemetry ≠ ter observabilidade completa: ele apenas padroniza a coleta; definir o que registrar continua sendo responsabilidade do desenvolvedor
- Não é a mesma coisa que tracing: tracing mostra o fluxo entre serviços; Wide Event fornece o contexto interno do serviço
- A separação “logs são para debugging, métricas são para dashboards” é desnecessária — Wide Event atende aos dois usos
- A ideia de que “dados de alta cardinalidade são caros” está ultrapassada; bancos modernos como ClickHouse e BigQuery os processam com eficiência
Efeitos da adoção de Wide Event
- O debugging deixa de ser uma escavação (archaeology) e vira análise (analytics)
- Em vez de usar
grep em logs de 50 serviços para encontrar uma “falha de pagamento do usuário”,
passa-se para uma análise baseada em uma única query, como “consultar a taxa de falha de pagamento de usuários premium por código de erro”
- No fim, os logs deixam de ser uma ferramenta que contava mentiras e se tornam um ativo de dados que diz a verdade
1 comentários
Comentários do Hacker News
O texto era difícil de ler e dava a impressão de ter sido ajudado por IA. Ainda assim, a mensagem tinha valor, e teria sido melhor se fosse mais conciso
Alguns pontos em que pensei recentemente:
Nesse tema, é impossível não mencionar Charity Majors. Ela vem difundindo os conceitos de “wide events” e “observability” há mais de 10 anos, e construiu a Honeycomb.io sobre essa filosofia.
Hoje em dia dá para implementar essa abordagem com várias ferramentas. O importante é capturar wide events com structured logs ou traces e usar ferramentas com visualizações ricas, como séries temporais e histogramas
Concordo parcialmente com o argumento do texto, mas há armadilhas em deixar apenas um único wide event. Se uma exceção ou timeout acontecer no meio da requisição, nada fica registrado.
Você também acaba perdendo os frameworks básicos de logging da linguagem e os logs das dependências.
Então o ideal é usar isso como uma camada adicional por cima dos logs existentes. Basta ter um ID por request/session e agregar depois em algo como ClickHouse
log.error(data)ewide_event.attach(error, data)são essencialmente a mesma coisaA apresentação e os exemplos interativos foram excelentes. Mas no fim tudo se resume a “adicione tags estruturadas aos logs”.
Sinto que wide logs não entregam ganho suficiente diante da complexidade e da perda de legibilidade.
Muitas vezes um simples
grep \"uid=user-123\" application.logjá resolve, então fico pensando se realmente faz sentido incluir até o método de entrega do usuário.(Aliás, no navegador Brave para Android os checkboxes não funcionaram)
grep '\"uid\": \"user-123\"'. Também dá para usar a opção--contextpara ver as linhas ao redorTrabalhei num ambiente de fabricação de semicondutores com um sistema que tinha milhares de participantes no message bus. Saíam 300 a 400 MB de logs por hora, mas ainda assim era totalmente gerenciável só com grep e ferramentas de CLI.
Os logs eram apenas a série temporal dos eventos; a análise detalhada era feita com consultas Oracle. Logs servem para entender a causalidade dos acontecimentos
Logs dizem “quando e o que aconteceu”; o “por quê” vem da combinação entre código, dados e eventos
Pessoalmente, acho interfaces como a stack ELK ruins para exploração intuitiva. É importante conseguir ler e seguir os logs de forma natural
O conselho no fim do texto — “logue todos os erros, exceções e requisições lentas” — é uma ideia perigosa.
Por exemplo, se uma dependência ficar lenta, o volume de logs pode explodir em 100x.
Em situações de incidente, o serviço deveria fazer menos trabalho para se recuperar, mas essa explosão de logs pode acabar provocando uma falha em cascata
Quanto maior o volume de logs, mais a taxa de amostragem se ajusta automaticamente para não sobrecarregar o sistema
trace_id mod 100 == 0Em software moderno, é difícil que um único log explique completamente “o que aconteceu”.
Por isso são necessárias correlação vertical (Vertical correlation) e correlação horizontal (Horizontal correlation).
Entre as camadas da stack, o mesmo valor de correlação deve ser compartilhado; e na comunicação entre sistemas, também é preciso haver correlação entre pares.
Adicionar esses valores a APIs ou protocolos é difícil, mas, se você projetar um transaction ID desde o início, o rastreamento completo se torna possível
Acho que registrar um domínio separado só para um único texto tem pouca durabilidade.
Como é preciso pagar renovação todo ano, me parece melhor usar um blog pessoal ou um subdomínio.
Algo como logging-sucks.boristane.com seria uma forma melhor
Sobre a afirmação de que “logs são relíquias da era monolítica”, eu acho que logs locais ainda são válidos.
O papel original deles é registrar a conversa de um processo local; para entender o que acontece em outros servidores, é preciso transaction tracing.
Só de olhar os logs certos, no lugar certo, muitas vezes já dá para chegar à causa raiz
Logs com contexto rico, combinados com um mecanismo de análise, também podem ser usados para melhorar o produto
Concordo com a frase “em vez de logar o que o código faz, logue o que aconteceu com a requisição”, mas o autor pareceu ter pouca experiência.
Eu chamo isso de “bug parts logging” e acho que ele deveria incluir sinais precursores como caminho de execução, contagem e tempo.
Logging é diferente de métricas ou auditoria (audit). Se o logging falhar, o processamento deve continuar; se a auditoria falhar, isso é crítico.
Como no conceito de “historian” em sistemas SCADA, é preciso separar observáveis (observables) de avaliativos (evaluatives).
Por exemplo, eventos detalhados de um sensor de combustível podem ser úteis para diagnóstico, mas são desnecessários para a pergunta “dá para chegar ao destino?”.
No fim, o mais importante é definir com clareza o que observar e o que avaliar
Armazenamento, transformação e consulta podem variar, mas os pontos de consumo e mecanismos podem ser projetados da mesma forma.
Isso simplifica o desenho do sistema e ainda permite reprocessar logs armazenados a longo prazo depois