Em um sistema distribuído, uma requisição raramente termina no serviço que a recebeu. Ela pode atravessar um gateway, uma fila, vários serviços, caches e bancos de dados. Quando a latência aumenta ou uma operação falha, logs isolados respondem pouco: é necessário conectar evidências para entender onde o problema começou, qual dependência foi afetada e quem foi impactado.
Observabilidade é a capacidade de inferir o estado interno de um sistema a partir dos sinais que ele emite. OpenTelemetry fornece um padrão aberto para produzir, propagar, coletar e exportar esses sinais sem acoplar a instrumentação a um fornecedor específico.
1. Os sinais respondem a perguntas diferentes
OpenTelemetry organiza a telemetria principalmente em três sinais complementares:
- Traces: mostram o caminho de uma operação entre componentes e ajudam a localizar o trecho lento ou com erro.
- Métricas: agregam comportamento ao longo do tempo, úteis para alertas, capacidade e objetivos de nível de serviço.
- Logs: preservam o contexto detalhado de eventos específicos para investigação.
Não substitua um sinal por outro. Uma métrica pode indicar crescimento na taxa de erros; o trace identifica a dependência envolvida; os logs correlacionados ajudam a explicar a causa. O objetivo não é coletar tudo, mas produzir sinais que respondam às perguntas operacionais mais importantes.
2. Contexto é o elo entre serviços
Um trace é composto por spans. Cada span representa uma unidade de trabalho — por exemplo, uma requisição HTTP, uma consulta ao banco ou o consumo de uma mensagem. A relação de paternidade entre eles forma a árvore da operação distribuída.
Para essa árvore sobreviver aos limites entre processos, o contexto precisa ser propagado. Em HTTP, o padrão W3C Trace Context define os cabeçalhos traceparent e tracestate; bibliotecas de instrumentação usam essas informações para continuar o trace no próximo serviço.
flowchart LR
Client[Cliente] --> Gateway[API Gateway]
Gateway --> Checkout[Serviço de checkout]
Checkout --> Payment[Serviço de pagamento]
Checkout --> Collector[OpenTelemetry Collector]
Payment --> Collector
Collector --> Backend[Backend de observabilidade]O Collector recebe a telemetria, pode enriquecer, filtrar, amostrar e encaminhar os dados. Essa separação reduz o acoplamento entre aplicações e destinos de observabilidade, além de centralizar decisões de processamento.
3. Instrumente as fronteiras primeiro
Uma adoção eficiente começa pelas operações que representam valor ou risco para o negócio:
- Requisições de entrada, tarefas assíncronas e consumidores de fila.
- Chamadas HTTP/gRPC para dependências externas.
- Consultas a banco, cache e mensageria.
- Operações de domínio que precisam de contexto adicional para diagnóstico.
Antes de criar atributos próprios, aplique as convenções semânticas do OpenTelemetry. Elas dão nomes consistentes a dados como método HTTP, nome do serviço, operação de banco e tipo de erro. A consistência permite consultar vários serviços sem depender de convenções locais.
Evite cardinalidade sem controle
Rótulos e atributos são úteis, mas cada valor distinto aumenta o número de séries de métricas e o volume de armazenamento. Não use identificadores de pedido, e-mail, URL completa ou request ID como rótulos de métricas. Esses valores podem ser atributos de um trace — desde que não contenham dados sensíveis e que a política de retenção permita —, mas métricas devem usar dimensões pequenas e previsíveis, como rota normalizada, código de resposta e operação.
4. Exemplo de instrumentação manual em Go
O trecho abaixo é ilustrativo e pressupõe que s.gateway já tenha sido definido. Ele cria um span para uma operação de negócio, associa um atributo útil e registra a falha no mesmo contexto da requisição.
package checkout
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
)
var tracer = otel.Tracer("kleber.dev/checkout")
func (s *Service) Authorize(ctx context.Context, orderID string) error {
ctx, span := tracer.Start(ctx, "checkout.authorize")
defer span.End()
span.SetAttributes(attribute.String("order.id", orderID))
if err := s.gateway.Authorize(ctx, orderID); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "falha ao autorizar pagamento")
return err
}
return nil
}
Em um sistema real, o ctx devolvido por tracer.Start deve ser repassado a todas as chamadas subsequentes. É essa prática, combinada à instrumentação das bibliotecas HTTP e de banco de dados, que preserva a continuidade do trace.
O atributo order.id é apenas um exemplo de correlação. Avalie se ele revela um identificador sensível ou cria custo excessivo no backend; quando houver risco, use um identificador interno adequado, remova-o no Collector ou não o registre.
5. Métricas orientadas aos sinais de ouro
Para serviços de requisição, um conjunto inicial de métricas deve permitir acompanhar os quatro sinais de ouro:
- Latência: duração de operações importantes, idealmente em histogramas.
- Tráfego: taxa de requisições, mensagens ou trabalhos processados.
- Erros: falhas por operação e por classe de resposta.
- Saturação: uso de recursos que limita a capacidade, como pools, filas ou conexões.
Essas métricas devem estar associadas a uma ação. Um alerta de taxa de erros, por exemplo, precisa apontar para a rota, o serviço e o procedimento de investigação. Alertas sem um limiar ligado a impacto no usuário tendem a gerar ruído.
6. Amostragem, privacidade e custo são decisões de arquitetura
Guardar todos os traces em produção pode ser caro, mas amostrar cedo demais pode apagar justamente a evidência de uma falha rara. Comece com uma taxa conhecida, aumente a retenção de erros e traces lentos e revise a estratégia com base em volume, custo e capacidade de diagnóstico.
Telemetria também é dado de produção. Não registre senhas, tokens, conteúdo de cabeçalhos de autorização, payloads completos ou dados pessoais sem uma necessidade clara e controles adequados. Defina uma política de atributos permitidos e aplique filtragem no Collector como camada adicional de proteção.
7. Um roteiro de adoção incremental
- Escolha um fluxo crítico e escreva as perguntas que o time precisa responder durante um incidente.
- Instrumente entradas e dependências desse fluxo, garantindo a propagação de contexto.
- Envie traces, métricas e logs para um ambiente de teste e valide a correlação.
- Defina atributos obrigatórios, limites de cardinalidade e regras de remoção de dados sensíveis.
- Crie painéis e alertas ligados a objetivos de serviço, não apenas a recursos de infraestrutura.
- Revise a instrumentação após incidentes reais: toda investigação deve melhorar os sinais disponíveis na próxima vez.
Conclusão
OpenTelemetry não torna um sistema observável por si só; ele padroniza a produção de evidências. A diferença aparece quando o contexto atravessa os serviços, os sinais respondem a perguntas concretas e a telemetria é tratada como parte da arquitetura — com contrato, custo e privacidade.
No próximo artigo, podemos conectar essa telemetria a entrega contínua: usar métricas e traces para validar uma mudança antes de ampliar sua exposição.

Comentários