37 pontos por GN⁺ 2025-12-22 | 1 comentários | Compartilhar no WhatsApp
  • 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
    1. Não decide o que deve ser registrado
    2. Não adiciona automaticamente contexto de negócio (por exemplo, nível de assinatura, valor do carrinho etc.)
    3. 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
    1. Erros (como 500) são sempre armazenados
    2. Requisições lentas (p99 ou acima) são sempre armazenadas
    3. Usuários VIP e sessões com flags específicas são sempre armazenados
    4. 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

 
GN⁺ 2025-12-22
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:

    • Como há autenticação em toda a stack, comecei a incluir o user id em todas as linhas de log. Isso tornou muito mais fácil ver a experiência do usuário como um todo
    • Registrar erros em uma linha separada dos logs da requisição é trabalhoso. Dá para filtrar por trace, mas é difícil montar consultas como “mostre apenas erros relacionados a requisições 5xx”
    • Só adicionar esse contexto não basta; também é preciso ensinar aos colegas que novos campos existem. Já vi muita gente sofrendo à toa por não saber disso
    • Investir em ferramentas de tracing melhores permite um nível de depuração que logs simples não conseguem oferecer. É como expandir a ideia de usar user id em traces
    • Se o codebase tiver o conceito de request ID, isso também permite rastrear o comportamento do usuário com mais precisão
    • Se você aplicar TID de forma obrigatória em todo o serviço, qualquer equipe consegue rastrear a transação inteira com um único TID
    • Comentários desse tipo, de “isso tem cheiro de IA”, logo devem passar a ser vistos como uma cultura criticada
  • 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

    • Mas o termo “observability” em si não foi criado por ela. Já era um conceito usado em várias áreas há décadas. Ela é uma profissional influente da prática, mas não a criadora do termo
    • O blog dela e a história por trás da Honeycomb valem muito a leitura para quem trabalha na área. Foi uma das primeiras equipes a perceber o valor dessa abordagem
    • O texto parecia tanto com o estilo dela que eu achei que no final apareceria uma propaganda da Honeycomb, e me surpreendi quando não apareceu
    • No ecossistema .NET, Nick Blumhardt já tratava de structured logging há muito tempo, e Seq e Serilog davam suporte a isso
    • O conteúdo dela é bom, mas ninguém “transformou observability em marca”. Vale respeitar sem exagerar nas afirmações
  • 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

    • Se o problema é visibilidade da camada intermediária, então o evento não é wide o suficiente. log.error(data) e wide_event.attach(error, data) são essencialmente a mesma coisa
    • Logs como “connection X:Y accepted at Z ns” e “closed at Z ns” são muito úteis para depurar sistemas lentos
    • Eu resolvi isso num framework PHP criando uma LoggerInterface. Capturo exceções em um handler global e salvo em formato wide no banco. Tem um pouco de boilerplate, mas funciona tão bem que agora faz falta quando não existe
  • A 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.log já 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)

    • Se os logs forem JSON, ainda dá para buscar com grep '\"uid\": \"user-123\"'. Também dá para usar a opção --context para ver as linhas ao redor
  • Trabalhei 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 servem para entender a timeline, não para carregar todos os dados de request/response. Se você coloca informação demais, fica mais difícil de entender.
      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
    • 400 MB de logs por hora, na prática, nem é tanto assim. Por isso um grep simples já dá conta
  • 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

    • Na Cloudflare, usam amostragem adaptativa. Lotes de logs são agrupados em buckets por campo, e de cada bucket ficam só a raiz quadrada ou o logaritmo da quantidade de entradas.
      Quanto maior o volume de logs, mais a taxa de amostragem se ajusta automaticamente para não sobrecarregar o sistema
    • Esses limiares mágicos são perigosos. Valores como P(99) precisam ser atualizados dinamicamente. Buscar os valores reais periodicamente pelo OTEL provider é mais seguro
    • Serviços em produção deveriam ser projetados para que a coleta de logs escale conforme a demanda. Só o buffering em disco local já ajuda bastante
    • Em serviços de alto tráfego, dá para amostrar requisições saudáveis com algo como trace_id mod 100 == 0
    • Se logs viram gargalo, então o sistema foi mal projetado. Um logging eficiente consegue lidar com centenas de milhões de eventos por segundo
  • Em 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

    • Na real, esse domínio e o texto são uma promoção do SaaS de observability do autor. Precisa de conta Cloudflare, mas como é grátis, parece uma estratégia de marketing de longo prazo. Ainda assim, foi útil, e como eu também tenho conta CF, talvez eu use
    • Esse texto está numa linha parecida com “Give people something to link to”, de Simon Willison
    • Isso está mais para uma landing page de geração de leads para marketing digital do que para um post de blog. A promoção do serviço é bem clara
  • 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

    • Mas logs não servem apenas para análise de causa raiz; eles também podem gerar insights de negócio, como quem foi afetado, correlação entre performance e entrada, impacto de vulnerabilidades de segurança etc.
      Logs com contexto rico, combinados com um mecanismo de análise, também podem ser usados para melhorar o produto
    • Diante da frase “uma requisição passa por 15 serviços e 3 bancos de dados”, também houve quem respondesse que esse tipo de complexidade deveria ser evitado
    • Para mim, APN/Kibana já são suficientes para análise de logs
  • 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

    • Eu apoio uma “teoria unificada da observabilidade”. Logs, métricas e auditoria são todos fluxos de bits e podem ser convertidos sem perda.
      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