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]
Fluxo de telemetria com propagação de contexto

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:

  1. Requisições de entrada, tarefas assíncronas e consumidores de fila.
  2. Chamadas HTTP/gRPC para dependências externas.
  3. Consultas a banco, cache e mensageria.
  4. 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

  1. Escolha um fluxo crítico e escreva as perguntas que o time precisa responder durante um incidente.
  2. Instrumente entradas e dependências desse fluxo, garantindo a propagação de contexto.
  3. Envie traces, métricas e logs para um ambiente de teste e valide a correlação.
  4. Defina atributos obrigatórios, limites de cardinalidade e regras de remoção de dados sensíveis.
  5. Crie painéis e alertas ligados a objetivos de serviço, não apenas a recursos de infraestrutura.
  6. 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.

Referências