Observabilidade
A capacidade de entender o estado interno de um sistema a partir das suas saídas externas — sem precisar implantar novo código para investigar um problema. Os três pilares são Logs, Métricas e Distributed Tracing.
Intenção
Observabilidade é a propriedade de um sistema que permite inferir seu estado interno apenas analisando as saídas que ele produz. Em produção você não tem acesso a um debugger — o que você tem são logs, métricas e traces. Sem instrumentação adequada, investigar um incidente se torna adivinhação.
O termo vem da teoria de controle: um sistema é "observável" se seu estado pode ser determinado a partir das suas saídas externas ao longo do tempo. No contexto de software, isso significa que quando algo dá errado em produção, você consegue responder: o quê aconteceu? (logs), com que frequência e intensidade? (métricas) e onde exatamente no fluxo ocorreu? (tracing). Sem as três respostas, a investigação opera no escuro.
Problema
Sistemas distribuídos modernos — com dezenas de microsserviços, chamadas síncronas e assíncronas, filas, caches e bancos de dados — são inerentemente opacos. Uma requisição do usuário pode atravessar oito serviços antes de retornar resposta; quando falha, a causa pode estar em qualquer um deles ou na interação entre eles.
- Logs sem correlação: quando cada serviço escreve logs independentes sem identificador comum, correlacionar o comportamento de uma requisição específica entre serviços exige horas de grep manual.
- Métricas só de média: a média de latência pode parecer saudável enquanto 1% dos usuários experimenta timeouts de 10 segundos. Percentis (p95, p99) revelam o que a média esconde.
- Sem tracing, sem localização do gargalo: saber que "o serviço de pedidos ficou lento" é diferente de saber que "a query SQL de busca de estoque dentro do serviço de pedidos levou 800 ms naquela chamada específica".
Como funciona
Logs — registro de eventos discretos
Logs são registros de eventos com timestamp, nível de severidade e dados contextuais. Logs estruturados em JSON são preferíveis a texto livre porque permitem filtragem, indexação e consulta em ferramentas como Elasticsearch, Loki ou CloudWatch Logs Insights.
Cada log deve incluir um Correlation ID (também chamado de TraceID) — um identificador único da requisição original que permanece constante enquanto ela atravessa todos os serviços. Sem esse ID, correlacionar logs de diferentes serviços é inviável em qualquer volume real de tráfego.
// Log estruturado — filtrável e indexável
{"timestamp":"2024-01-15T14:23:01Z","level":"ERROR",
"service":"order-svc","msg":"payment timeout",
"traceId":"abc-123","userId":"u-456","durationMs":5032}
// Log texto livre — difícil de filtrar programaticamente
[ERROR] 2024-01-15 14:23:01 Payment timeout for user u-456
Níveis de severidade: DEBUG (detalhes de desenvolvimento),
INFO (eventos de negócio normais), WARN (situação
anormal mas recuperável), ERROR (falha que requer atenção).
Em produção, use INFO como padrão — DEBUG gera
volume e custo desproporcionais.
Métricas — valores numéricos agregados
Métricas são observações numéricas coletadas ao longo do tempo e agregadas em séries temporais. São mais eficientes que logs para análise de tendências e alertas. Os três tipos fundamentais:
-
Counter: valor monotônico que só aumenta. Ex.: total de
requisições, total de erros. Útil para calcular taxas (
rate()em Prometheus). Nunca decresce — reinicia apenas quando o processo reinicia. - Gauge: valor instantâneo que sobe e desce. Ex.: conexões abertas, memória usada, tamanho de fila. Captura o estado atual do sistema.
- Histogram: distribui observações em buckets configuráveis e permite calcular percentis (p50, p95, p99). Essencial para latência, porque a média esconde o tail — p99 pode ser 100x a média em sistemas com distribuição de cauda longa.
O RED Method (por Tom Wilkie) define as três métricas essenciais para qualquer serviço: Rate (volume de requisições por segundo), Errors (taxa de erros) e Duration (distribuição de latência). Qualquer SLO começa por aqui. O stack mais comum em open source é Prometheus para coleta e Grafana para visualização.
Distributed Tracing — rastreamento de requisições
Distributed Tracing acompanha uma requisição enquanto ela atravessa múltiplos serviços. Cada unidade de trabalho — uma chamada HTTP, uma query de banco, uma operação de cache — é um Span: um intervalo com tempo de início, duração, atributos e referência ao span pai. Spans relacionados formam um Trace.
O TraceID é propagado entre serviços via headers HTTP. O padrão atual é o
W3C Trace Context com o header traceparent:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^
ver trace-id (16 bytes) parent-span-id flags
OpenTelemetry é o padrão atual para instrumentação — uma API e SDK vendor-neutro que exporta telemetria para qualquer backend (Jaeger, Zipkin, Grafana Tempo, Datadog, Honeycomb). Adotar OpenTelemetry desde o início evita lock-in em ferramentas de observabilidade.
Em alta volumetria, coletar 100% dos traces é proibitivo em custo e overhead. Head-based sampling decide no início da requisição (ex.: 1–10% das requisições); tail-based sampling decide ao final, retendo 100% dos traces com erros e descartando os saudáveis — mais inteligente, mais complexo de implementar.
Correlação entre os três pilares
Os três pilares valem individualmente, mas a observabilidade real emerge quando estão correlacionados. O mesmo TraceID que aparece no log de erro permite navegar diretamente ao trace daquela requisição específica, ver quais spans estavam lentos e então ir às métricas de latência daquele serviço no mesmo instante. Essa navegação fluida (log → trace → métrica) é o que diferencia observabilidade de monitoramento tradicional.
Quando usar
- Qualquer serviço em produção: os três pilares são pré-requisito, não diferencial. Comece com logs estruturados e métricas RED; adicione tracing depois.
- Microsserviços e sistemas distribuídos: tracing é especialmente valioso quando uma requisição atravessa múltiplos serviços. É impossível correlacionar manualmente o comportamento de 10 serviços sem TraceID e cascata de spans.
- Ao definir SLOs: os pilares fornecem os dados para medir SLIs — latência p99, taxa de erros, disponibilidade — e verificar se os objetivos estão sendo cumpridos.
Quando evitar (ou dimensionar com cuidado)
- Tracing com 100% de sampling em alta volumetria: em serviços com 10 k req/s, armazenar todos os traces é proibitivo. Use head-based ou tail-based sampling. Alertas e métricas não precisam de sampling.
- Logs DEBUG em produção continuamente: esse nível pode gerar GBs por hora e custo de ingestão desproporcional. Use INFO como padrão; DEBUG apenas em janelas específicas de investigação.
Prós e contras
Prós
- Reduz drasticamente o MTTR: incidentes são investigados com dados concretos, não com suposições.
- Permite SLOs baseados em dados reais — p99 de latência, taxa de erros, disponibilidade medida.
- Tracing revela gargalos invisíveis em métricas de serviço isoladas.
- OpenTelemetry como padrão evita lock-in em vendor de observabilidade.
Contras
- Custo: armazenamento de logs e traces em alta volumetria pode ser significativo — requer gestão ativa de retenção e sampling.
- Overhead de instrumentação: tracing adiciona latência (~1 ms) e consumo de CPU por requisição. Sampling mitiga, mas não elimina.
- Complexidade de setup: configurar OpenTelemetry, Prometheus, Grafana e Jaeger e correlacionar tudo tem curva de aprendizado relevante.
- Instrumentação retroativa é muito mais cara: adicionar observabilidade a código legado sem injeção de dependência é ordens de magnitude mais trabalhoso do que instrumentar ao desenvolver.
Armadilhas comuns
1. Logs em texto livre
Logs sem estrutura — [ERROR] Payment failed for user 12345
— são legíveis para humanos mas impossíveis de filtrar
programaticamente. Quando você precisa de "todos os erros do usuário X
nas últimas 2 horas" em um sistema com 1 k req/s, grep em texto livre
não é uma estratégia viável. Use JSON estruturado com campos indexáveis
desde o primeiro dia.
2. Métricas sem percentis — a armadilha da média
A média de latência pode estar saudável enquanto 1% dos usuários sofre timeouts de 30 segundos. Isso ocorre porque a média é sensível ao volume (muitas requisições rápidas diluem as lentas) mas insensível à cauda. Sempre monitore p95 e p99. Em SLAs voltados ao usuário, o percentil relevante costuma ser p99 — o "pior 1%" é o usuário mais impactado.
Prática: defina alertas no p99 de latência e na taxa de erros por rota. Média de latência como alerta gera tanto falsos negativos (não alertou quando devia) quanto falsos positivos (alertou por outliers isolados).
3. Tracing sem sampling — custo e overhead
Coletar 100% dos traces em um serviço com 5 000 requisições por segundo significa armazenar 432 milhões de traces por dia. Além do custo de armazenamento, a própria exportação de traces adiciona overhead de rede. Use sampling: head-based (1–10%) para casos gerais; tail-based (retém 100% dos traces com erros) para diagnóstico de falhas.
4. Observabilidade adicionada após o incidente
A instrumentação tem custo muito mais baixo quando implementada junto com o código. Adicionar observabilidade após o fato — especialmente em código legado sem injeção de dependência — é ordens de magnitude mais caro. Trate observabilidade como requisito funcional: o critério de aceite de qualquer serviço deve incluir "tem logs estruturados, métricas RED e traces com TraceID propagado".
Arquiteturas e padrões relacionados
SLA, SLO e SLI dependem diretamente de observabilidade: não é possível medir se um SLO de latência p99 está sendo cumprido sem métricas de histograma instrumentadas e alertas configurados.
Circuit Breaker é mais eficaz quando combinado com métricas: o estado do circuit (aberto/fechado/meio-aberto) deve ser uma métrica observável, e as decisões de abertura devem ser visíveis nos logs e traces.
API Gateway é um ponto natural de instrumentação: posicionado na borda, pode injetar TraceID em todas as requisições de entrada, coletar métricas RED de todos os serviços downstream e centralizar logs de acesso.
Filas de Mensagem adicionam complexidade ao tracing: o contexto de propagação (TraceID) precisa ser serializado nos metadados da mensagem para que o consumidor possa continuar o mesmo trace do produtor, mesmo processando a mensagem minutos depois.