Observabilidade na Prática: Logs, Métricas e Tracing em Produção
Observabilidade na Prática: Logs, Métricas e Tracing em Produção
Há uma diferença entre monitoramento e observabilidade que a maioria dos times aprende do jeito difícil — durante um incidente às 3 da manhã, quando todos os dashboards estão verdes e algo está claramente, inegavelmente quebrado.
Monitoramento diz quando coisas predefinidas dão errado. Você define thresholds, recebe alertas. Funciona bem para problemas que você já viu antes e pensou em instrumentar. Falha completamente para modos de falha novos — os que realmente te acordam à noite.
Observabilidade é a propriedade de um sistema que permite entender seu estado interno a partir de suas saídas externas. Um sistema observável permite fazer perguntas arbitrárias — "quais usuários estão experienciando esse modo de falha específico?", "o que mudou nos 15 minutos antes da latência disparar?" — sem precisar ter antecipado essas perguntas com antecedência.
A diferença não é filosófica. Ela determina se seu time passa incidentes executando scripts e correlacionando arquivos de log à mão, ou se consegue fazer a pergunta certa e obter a resposta em segundos.
Este artigo cobre como implementar observabilidade corretamente usando os três pilares — logs, métricas e tracing — com escolhas práticas de ferramental e exemplos reais de incidentes.
Os três pilares da observabilidade
Todo sistema observável emite três tipos de telemetria, e cada um responde uma classe diferente de pergunta.
Logs respondem "o que aconteceu?" São o registro narrativo de eventos no seu sistema — registros estruturados e com timestamp do que o código fez quando. Logs são o sinal de maior informação: podem conter contexto arbitrário sobre qualquer evento.
Métricas respondem "como o sistema está se comportando ao longo do tempo?" São medições numéricas agregadas ao longo do tempo — taxa de requisições, taxa de erros, percentis de latência, uso de CPU, consumo de memória. Métricas são o sinal de menor cardinalidade: baratos de armazenar, fáceis de consultar, perfeitos para alertas e tendências.
Traces respondem "o que esse request específico fez?" Seguem uma única operação (um request de usuário, um job em background, uma tarefa agendada) por todos os componentes que tocou — serviços, bancos de dados, caches, filas — com informações de tempo para cada etapa.
O erro que a maioria dos times comete é tratar esses como sistemas separados com propósitos separados. A observabilidade real vem de conectá-los: um trace se liga aos logs emitidos durante aquele trace, e à série temporal de métricas que disparou no mesmo timestamp.
OpenTelemetry: o padrão unificado
Antes de mergulhar na implementação, entender o OpenTelemetry é essencial, porque ele muda o cenário de ferramental.
OpenTelemetry (OTel) é o padrão aberto apoiado pela CNCF para instrumentação de telemetria. Ele fornece:
- APIs — interfaces específicas de linguagem para emitir traces, métricas e logs do seu código.
- SDKs — a implementação dessas APIs para cada linguagem suportada (Go, Python, Java, JavaScript, .NET, Ruby, e mais).
- Um protocolo (OTLP) — um protocolo de rede neutro a fornecedor para enviar telemetria dos seus serviços para qualquer backend.
- Coletores — agentes que recebem, processam e exportam telemetria da sua infraestrutura.
O benefício crítico: você instrumenta seu código uma vez e pode enviar essa telemetria para qualquer backend — Grafana, Datadog, Honeycomb, Jaeger, AWS X-Ray — mudando configuração, não código. Você evita lock-in de fornecedor na camada de instrumentação.
Em 2024, OpenTelemetry é o padrão correto para toda nova instrumentação. Se você está usando um SDK específico de fornecedor, está criando um custo de migração que vai se materializar eventualmente.
Implementando logging estruturado
Logs de texto bruto são um antipadrão. Pesquisar em gigabytes de mensagens [2026-03-29 03:17:42] ERROR Algo deu errado requer grep, é lento e não pode ser filtrado ou agregado de forma confiável.
Logging estruturado emite eventos de log como pares chave-valor (tipicamente JSON), tornando-os consultáveis, filtráveis e agregáveis por qualquer backend de observabilidade.
Um evento de log bem estruturado:
{
"timestamp": "2026-03-29T03:17:42.000Z",
"level": "error",
"service": "pagamento-processador",
"version": "2.4.1",
"trace_id": "abc123def456",
"span_id": "789ghi012",
"user_id": "usuario_9872643",
"order_id": "pedido_8812734",
"event": "pagamento_falhou",
"error": "stripe_timeout",
"valor_centavos": 24999,
"moeda": "brl",
"duracao_ms": 5023,
"message": "Pagamento falhou após 5023ms: timeout da API Stripe"
}
Observe o que isso habilita:
- Encontrar todas as falhas de pagamento de um usuário específico:
user_id = "usuario_9872643" AND event = "pagamento_falhou" - Encontrar todos os timeouts do Stripe na última hora:
error = "stripe_timeout" AND timestamp > now-1h - Correlacionar com um trace de request específico:
trace_id = "abc123def456" - Alertar sobre taxa de erro:
count(level="error") / count(*) > 0.05
Os campos que todo evento de log deve ter
Sempre:
timestamp— ISO8601 com precisão de milissegundolevel— error, warn, info, debugservice— nome do serviço emissorversion— versão deployada do serviçotrace_id— liga ao trace distribuído
Quando disponível (injetado do contexto da requisição):
user_id,account_id,org_id— o sujeito da operaçãorequest_id— ID único para a requisição de entrada- IDs de entidade relevantes (
order_id,payment_id, etc.)
Para erros:
error— código de erro legível por máquinaerror_detail— detalhe legível por humanostack_trace— para exceções inesperadas
Níveis de log como disciplina
Use níveis deliberadamente:
error— falhas inesperadas que requerem investigação ou ação imediata. Deve sempre gerar alerta ou page.warn— algo inesperado mas tratado. Degrada graciosamente. Vale monitorar o acúmulo.info— eventos de negócio significativos. "Pedido realizado." "Usuário cadastrado." "Job agendado iniciado/concluído." Mantenha sinal-ruído alto.debug— estado interno útil durante desenvolvimento. Desativado em produção por padrão; deve ser ativável por serviço sem redeployment.
O erro mais comum: tratar toda linha de log como igualmente importante. Se 80% dos seus logs são info e cada request gera 50 deles, seu sinal está enterrado no ruído.
Implementando métricas corretamente
Métricas são a fundação dos alertas. São baratas de armazenar (uma série temporal de números), rápidas de consultar e a ferramenta certa para tendências, thresholds e rastreamento de SLO.
Os quatro sinais de ouro
O livro de Site Reliability Engineering do Google definiu quatro sinais que, se medidos para qualquer serviço, oferecem visibilidade quase completa da saúde desse serviço:
- Latência — quanto tempo leva para servir uma requisição. Distinga entre a latência de requisições bem-sucedidas e falhas.
- Tráfego — quanta demanda está sendo colocada no sistema. Requisições por segundo, mensagens processadas por minuto, volume de dados.
- Erros — a taxa de requisições falhas. Falhas vs. total, distinguindo HTTP 500s explícitos, falhas implícitas (HTTP 200 com conteúdo errado) e falhas de política (comprometido com SLA de <1s mas respondendo em 2s).
- Saturação — quão "cheio" seu serviço está. CPU, memória, disco, rede — qualquer que seja o recurso mais restrito. Também profundidade de fila para sistemas assíncronos.
Percentis em vez de médias
Latência média é quase sempre a métrica errada para alertar. Um sistema respondendo em 50ms para 99% das requisições e 5000ms para 1% tem uma média de ~99ms — aparentemente bom. Mas 1% das requisições a 5 segundos significa que 1 em 100 usuários está tendo uma experiência terrível.
Use percentis:
- P50 (mediana) — a experiência típica do usuário.
- P95 — a experiência para um usuário no 95º percentil. Frequentemente o que "a maioria dos usuários lentos" está experienciando.
- P99 — seu usuário no pior décimo percentil. Frequentemente onde problemas de infraestrutura aparecem primeiro.
- P99.9 — a experiência de um em mil. Crítico para sistemas financeiros, saúde e qualquer lugar onde o pior caso tem consequências graves.
Para um fluxo de checkout, latência P99 abaixo de 2 segundos pode ser o seu SLO. Definir o alerta no P99, não no P50, significa que você detecta degradação de latência de cauda antes que se torne uma experiência da maioria.
SLOs e error budgets
Service Level Objectives (SLOs) são a formalização de "como se parece o bom?". Um SLO é uma meta para uma métrica ao longo de uma janela de tempo:
- 99,9% das requisições para a API de checkout concluem em menos de 2 segundos em uma janela deslizante de 30 dias.
- 99,95% das requisições de autenticação têm sucesso em uma janela deslizante de 28 dias.
Um error budget é o complemento: a quantidade permitida de problemas. Com 99,9% de disponibilidade, você tem 43,8 minutos de downtime permitido por mês. Quando o error budget está saudável, times podem se mover rápido. Quando está esgotado, confiabilidade tem prioridade sobre velocidade de features.
Alertas baseados em SLO são fundamentalmente diferentes dos baseados em threshold. Em vez de alertar quando a taxa de erros supera 5%, você alerta quando está queimando error budget mais rápido do que seu período de SLO permite — antes que o budget se esgote.
Implementando distributed tracing
Distributed tracing é o mais difícil dos três pilares de implementar corretamente e o mais valioso quando você o faz.
Um trace é um grafo acíclico dirigido de spans. Cada span representa uma unidade de trabalho: um serviço tratando uma requisição, uma query de banco de dados, uma chamada a uma API externa. Spans têm:
- Um ID de span único
- O ID do span pai (que cria a estrutura de árvore)
- Um trace ID (compartilhado por todos os spans no mesmo ciclo de vida de requisição)
- Tempo de início e duração
- Nome da operação
- Atributos (contexto chave-valor: método HTTP, statement DB, user ID)
- Status (OK, Error)
- Eventos (anotações pontuais dentro do span)
Propagação: o mecanismo que faz o tracing funcionar
Tracing só funciona quando o contexto de trace é propagado além das fronteiras de serviço. Quando o Serviço A chama o Serviço B, ele deve incluir o trace ID e span ID atual nos headers da requisição de saída. O Serviço B lê esses headers, cria um span filho e inclui o contexto pai em quaisquer chamadas downstream que faça.
O OpenTelemetry lida com isso automaticamente para a maioria das bibliotecas comuns (clientes HTTP, gRPC, messaging). O padrão W3C Trace Context define o formato de header (traceparent), garantindo interoperabilidade entre diferentes sistemas de tracing.
Um exemplo real: depurando um pico de latência no checkout
Imagine este cenário: a latência P99 na sua API de checkout dispara de 800ms para 4,2 segundos. Seu alerta do Grafana dispara. Veja como a observabilidade torna isso tratável.
Passo 1: Métricas estreitam a janela de tempo. O pico começou exatamente às 14:23:07 UTC. A taxa de erros não mudou — é puramente um problema de latência.
Passo 2: Você encontra um trace lento. No seu backend de tracing (Jaeger/Grafana Tempo), você filtra por traces de checkout durante aquela janela com duração > 2 segundos. Você encontra dezenas.
Passo 3: O trace revela o gargalo. Abrindo um trace lento, você vê:
checkout-api (total: 4198ms)
├── auth-service (12ms) ← ok
├── inventory-service (4100ms) ← AQUI
│ └── postgres query: SELECT * FROM inventory WHERE sku IN (...) (4089ms)
└── payment-service (23ms) ← ok
Passo 4: Os atributos do span dão a query. O span do postgres inclui o texto da query como atributo. É um SELECT * FROM inventory WHERE sku IN (...) — uma query executando sobre uma tabela que cresceu significativamente nas últimas 24 horas. Um índice ausente.
Passo 5: Logs confirmam o diagnóstico. Filtrando logs com trace_id = [ID do trace lento], você vê o serviço de inventory logando um aviso: "Tempo de execução da query 4089ms excedeu o threshold de query lenta de 1000ms".
Sem distributed tracing, essa investigação pode levar uma hora. Com ele, do alerta à causa raiz são cinco minutos.
O stack de observabilidade: escolhas práticas de ferramental
O stack open-source (ecossistema Grafana)
Para times que querem possuir sua infraestrutura de observabilidade:
| Função | Ferramenta | |---|---| | Armazenamento de métricas | Prometheus + Thanos (para retenção de longo prazo) | | Armazenamento de logs | Grafana Loki | | Armazenamento de traces | Grafana Tempo | | Visualização | Grafana | | Alertas | Grafana Alertmanager | | Instrumentação | OpenTelemetry SDK + Collector |
O stack Grafana é pronto para produção, extremamente maduro e gratuito para operar. O custo operacional (gerenciar Prometheus, Loki e Tempo) é não trivial em escala — seja realista sobre a capacidade do seu time de rodar essa infraestrutura.
O stack gerenciado
Para times que querem focar em produto em vez de infraestrutura de observabilidade:
- Datadog — a plataforma SaaS de observabilidade mais completa. Alertas best-in-class, APM e gerenciamento de logs. Caro em escala.
- Honeycomb — construído especificamente para observabilidade de alta cardinalidade. Excepcional para depuração orientada a queries. A melhor ferramenta para times operando sistemas distribuídos complexos.
- Grafana Cloud — Grafana + Loki + Tempo + Prometheus gerenciados. A economia do stack open-source sem o fardo operacional.
- AWS CloudWatch / X-Ray — viável se você está totalmente comprometido com AWS. Boa integração com o ecossistema AWS; a UX de observabilidade é mais fraca do que ferramentas de propósito específico.
Construindo uma filosofia de alertas que funciona
Alertas têm um modo de falha bem conhecido: fadiga de alerta. Quando cada coisa que vale um page tem um alerta, e muitos desses alertas são ruidosos, os times aprendem a ignorá-los. Quando um incidente real dispara, são 30 minutos antes de alguém investigar porque todos assumiram que era mais um falso positivo.
Princípios para alertas de alto sinal
Alerte em sintomas, não causas. Usuários experienciam sintomas: alta latência, taxa de erros elevada, funcionalidade degradada. Alerte nesses. "CPU está em 80%" é uma causa — pode ou não estar afetando usuários. "Latência P99 está acima do threshold do SLO" é um sintoma.
Todo alerta deve ser acionável. Se você não consegue apontar para uma entrada de runbook ou um caminho específico de investigação quando um alerta dispara, não deve ser um alerta. Alertas não acionáveis se tornam ruído.
Use tiers do PagerDuty/OpsGenie deliberadamente. Nem todo alerta deve acordar alguém. Use roteamento em camadas: page imediatamente para violações de SLO e eventos de serviço fora do ar; email ou Slack para degradação de nível warning que ainda não viola SLO.
Deduplique e suprima. Um único problema de infraestrutura (slowdown de banco de dados) pode disparar 50 alertas de 50 serviços. Agrupamento e deduplicação na sua ferramenta de alerta previne tempestades de 50 pages que paralisam engenheiros de plantão.
Execute revisões mensais de alertas. Categorize todo alerta que disparou no último mês: acionável e correto, ruidoso (falso positivo) ou não disparou mas deveria ter. Remova ou ajuste com base em evidências.
Resposta a incidentes em produção: observabilidade em ação
O verdadeiro teste do seu investimento em observabilidade é como ele muda a resposta a incidentes.
Um sistema bem observado segue esse padrão durante um incidente:
- Detecção — um alerta dispara em um sintoma voltado ao usuário (taxa de erros elevada, taxa de queima do SLO).
- Escopo — métricas mostram quais serviços e quais populações de usuários estão afetados, quando começou e se está melhorando ou piorando.
- Isolamento — traces distribuídos e logs correlacionados estreitam o problema para um serviço, query, endpoint ou dependência de terceiro específico.
- Diagnóstico — atributos de span e contexto de log revelam a falha específica: uma query ruim, um timeout mal configurado, uma dependência que começou a retornar erros.
- Mitigação — correção ou contorno é deployado. Métricas confirmam a recuperação em tempo real.
- Postmortem — o replay do trace recria a sequência exata de falha, informando a correção de longo prazo.
Sem observabilidade, os passos 2–4 são adivinhação. Com ela, são decisões baseadas em evidências.
Conselho prático para começar
Se você está partindo do zero, a sequência que evita mais dor:
- Logging estruturado primeiro — É o investimento de menor esforço e maior retorno. Escolha uma biblioteca de logging estruturado para sua stack e aplique-a. Logue os quatro campos: timestamp, level, service, trace_id.
- Métricas para os quatro sinais de ouro — Instrumente a fronteira principal do seu serviço. Taxa de requisição, taxa de erros, latência P95 e P99, e o recurso mais restrito. Defina SLOs e alertas iniciais.
- Adicione tracing para seu serviço de maior complexidade — Comece com um serviço. Valide que traces estão sendo emitidos e visíveis. Verifique a propagação de contexto para dependências downstream.
- Conecte os três pilares — Garanta que seus logs contêm o trace_id. Garanta que seus traces se ligam a logs na sua UI de consulta de logs. Garanta que seus dashboards de métricas têm links ancorados no tempo para traces relevantes.
- Declare seus SLOs oficialmente — Escreva-os onde o time possa ver. Isso transforma observabilidade de infraestrutura em um compromisso organizacional.
Reflexão final
Observabilidade não é uma compra de ferramenta. É uma prática que um time constrói ao longo do tempo — instrumenta, observa, aprende, ajusta. Os times que fazem isso bem não têm ferramentas melhores do que os que lutam. Eles têm uma cultura de tratar observabilidade como uma preocupação de engenharia de primeira classe, não uma reflexão tardia.
Os engenheiros que constroem sistemas verdadeiramente observáveis são os que perguntam "como vou depurar isso em produção?" antes de entregar uma feature — não depois do page das 3 da manhã.
Essa mentalidade é a diferença entre um sistema sobre o qual você pode raciocinar e um sistema que você só pode esperar que esteja funcionando.
Fique à frente da curva
Insights técnicos aprofundados sobre arquitetura de software, IA e engenharia. Sem enrolação. Um e-mail por semana.
Sem spam. Cancele quando quiser.