OpenTelemetry padroniza a geração e o transporte de traces e métricas. Em um trace, spans representam etapas relacionadas de uma operação, permitindo localizar latência e erros entre serviços.

Um trace normalmente começa na entrada de uma requisição e acompanha chamadas a bancos, filas e outros serviços. Cada span tem início, fim, contexto e atributos. A relação entre pais e filhos reconstrói o caminho da operação, mesmo quando ela atravessa processos. OpenTelemetry define APIs, SDKs, convenções semânticas e o protocolo OTLP, mas não armazena nem consulta os dados. Esse papel pertence ao Collector e ao backend escolhido.

API, SDK, instrumentação e Collector

A API é o contrato usado pelo código e por bibliotecas instrumentadas. O SDK implementa amostragem, processamento e exportação. Em uma biblioteca reutilizável, dependa preferencialmente da API: quem executa a aplicação decide qual SDK e exportador configurar. Em uma aplicação, inicialize o SDK uma única vez, antes de criar trabalho concorrente.

Instrumentação automática envolve bibliotecas conhecidas, como clientes HTTP e frameworks web, e cria spans sem alterar cada handler. Instrumentação manual acrescenta significado de negócio às operações importantes. As duas abordagens se complementam. Leia os spans gerados automaticamente antes de adicionar outros, pois duplicar uma chamada deixa o trace ruidoso e aumenta custo.

O Collector é um processo separado que recebe telemetria, aplica pipelines e exporta para um ou mais destinos. Ele permite trocar credenciais e backends sem colocar essa lógica em todas as aplicações. Também pode fazer batching, filtragem e controle de memória. A aplicação continua responsável por não produzir dados sensíveis.

Criar um span manual

python -m pip install opentelemetry-api opentelemetry-sdk
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("universopython.pedidos")


def calcular_total(itens: list[int]) -> int:
    with tracer.start_as_current_span("calcular_total") as span:
        span.set_attribute("pedido.quantidade_itens", len(itens))
        return sum(itens)

O exportador de console é útil para aprendizado. Em produção, envie OTLP para um Collector e configure processamento em lote. Não coloque valor do pedido, e-mail, token ou corpo completo como atributo.

Um exportador OTLP por gRPC pode ser configurado assim:

python -m pip install opentelemetry-exporter-otlp-proto-grpc
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor

exporter = OTLPSpanExporter(endpoint="http://collector:4317", insecure=True)
provider.add_span_processor(BatchSpanProcessor(exporter))

Use insecure=True apenas em uma rede local deliberadamente sem TLS, como um ambiente de desenvolvimento. Em produção, autentique o destino, valide certificados e entregue credenciais por um mecanismo de secrets. Prefira variáveis de ambiente padronizadas, como OTEL_EXPORTER_OTLP_ENDPOINT, quando a configuração precisa variar entre implantações.

O BatchSpanProcessor exporta fora do caminho principal e é apropriado para serviços. O SimpleSpanProcessor bloqueia a operação durante a exportação e serve sobretudo para testes e depuração. Antes de encerrar um worker curto, finalize o provider de forma ordenada para dar ao lote pendente a oportunidade de sair.

Registrar estado, exceções e eventos

Um span deve terminar com estado de erro quando a operação falha, mas nem todo status HTTP alto representa automaticamente um defeito interno. Siga as convenções semânticas da instrumentação. Em spans manuais, registre exceções sem anexar segredos:

from opentelemetry.trace import Status, StatusCode

with tracer.start_as_current_span("pedido.reservar") as span:
    try:
        reservar_estoque()
    except EstoqueIndisponivel as erro:
        span.record_exception(erro)
        span.set_status(Status(StatusCode.ERROR, "estoque indisponível"))
        raise

Mensagens de exceção podem carregar valores inesperados. Revise o que suas exceções incluem e aplique redaction antes da exportação quando necessário. Eventos são adequados para ocorrências pontuais dentro do span, como uma tentativa de retry. Não transforme cada linha de log em evento: isso duplica volume sem melhorar a investigação.

Instrumentar fronteiras e propagar contexto

Bibliotecas de instrumentação podem criar spans para frameworks e clientes HTTP. Confirme quais campos geram e mantenha versões compatíveis. Propague o contexto entre serviços pelos padrões suportados; ContextVar resolve estado local, mas não atravessa a rede sozinho. Veja contextvars em código assíncrono.

Na rede, o propagador injeta identificadores em cabeçalhos e o destinatário os extrai. O formato W3C Trace Context usa traceparent e, opcionalmente, tracestate. Não aceite um identificador recebido como autorização ou identidade: contexto de trace serve para correlação, não para controle de acesso. Em fronteiras não confiáveis, imponha limites ao baggage, que pode carregar pares adicionais e se propagar por vários serviços.

Filas exigem atenção especial. O produtor injeta contexto na mensagem; o consumidor o extrai e cria um novo span. Não reutilize o contexto atual de uma tarefa anterior em workers. Para processamento em lote, verifique a convenção aplicável e escolha links quando várias mensagens independentes contribuem para uma operação.

Escolher nomes e atributos sustentáveis

O nome do span descreve uma operação estável, não uma instância. Use HTTP GET /pedidos/{id} ou pedido.processar, nunca a URL completa nem o ID do pedido. Atributos bons ajudam a agrupar resultados: método, rota normalizada, sistema de banco ou resultado em um conjunto pequeno. Valores únicos, como UUID, aumentam cardinalidade e custo. Quando um identificador for indispensável para investigação, considere mantê-lo em logs correlacionados com controles de acesso.

Não anexe:

  • cabeçalhos Authorization, cookies ou tokens;
  • corpo completo de requisições e respostas;
  • e-mail, documento, endereço ou outro dado pessoal;
  • consultas SQL com parâmetros interpolados;
  • nomes de arquivo ou mensagens que possam conter dados do cliente.

Defina uma política de atributos, teste-a e aplique filtragem defensiva no Collector. A filtragem posterior reduz exposição no backend, mas o dado já percorreu a aplicação e a rede; a melhor proteção é não criá-lo.

Amostragem, custo e investigação

Amostragem decide quais traces serão registrados. ParentBased mantém a decisão recebida do span pai e evita traces quebrados; um sampler baseado em proporção limita volume. A decisão inicial não conhece o resultado futuro, então uma amostragem muito baixa pode descartar erros raros. Alguns backends ou Collectors oferecem amostragem posterior, depois de observar o trace, com custo de infraestrutura adicional.

Meça a taxa real, a quantidade de spans por trace e o tamanho dos atributos antes de escolher percentuais. Preserve uma rota para depuração controlada, sem permitir que clientes externos forcem amostragem cara. Para testes, use um exportador em memória e confirme nomes, relações e ausência de dados proibidos. Não baseie testes em IDs aleatórios.

Operar com falhas de telemetria

Observabilidade não deve derrubar a aplicação. Defina filas e timeouts do exportador, monitore descartes e trate indisponibilidade do Collector. Ao mesmo tempo, uma falha silenciosa deixa a equipe cega. Exponha métricas internas do pipeline e crie alertas para quedas persistentes de exportação.

Use nomes estáveis, como pedido.processar, e atributos com cardinalidade controlada. IDs únicos podem ser úteis para correlação, mas ampliam custo de indexação. Combine traces com logs estruturados e métricas, cada sinal respondendo a perguntas diferentes.

A documentação oficial do OpenTelemetry para Python e a especificação oficial de traces, consultadas em 22 de julho de 2026, informam conceitos, configuração e status dos sinais. Verifique o status antes de adotar APIs experimentais e fixe versões compatíveis dos pacotes de instrumentação.