1. Retomando: métricas e logs prontos, falta conectar os pontos
As mini apps desta série já expõem métricas (artigos 2 e 3) e enviam logs para o Loki (artigo 4). O que ainda falta é o terceiro pilar visto no artigo 1: traces, que mostram o caminho de uma requisição específica e onde exatamente o tempo foi gasto. Este artigo apresenta o OpenTelemetry, o padrão atual para gerar esse tipo de dado, e instrumenta as duas mini apps para produzir traces reais.
2. O que é o OpenTelemetry
OpenTelemetry (frequentemente abreviado "OTel") é um projeto da CNCF que define um conjunto de APIs, SDKs e um protocolo de transporte (o OTLP — OpenTelemetry Protocol) para gerar, processar e exportar dados de telemetria — métricas, logs e, principalmente neste artigo, traces — de forma neutra em relação a qual backend vai efetivamente armazenar e visualizar esses dados.
Na prática, isso significa que a aplicação se instrumenta uma vez, contra a API do OpenTelemetry, e decide depois, por configuração, para onde exportar — Prometheus, Loki, Jaeger, um vendor comercial, ou, como esta série vai fazer no próximo artigo, um coletor OpenTelemetry intermediário. Trocar de backend de observabilidade deixa de exigir reescrever a instrumentação.
3. Por que virou o padrão dominante
Antes do OpenTelemetry, existiam dois projetos concorrentes e incompatíveis tentando resolver o mesmo problema: OpenTracing (focado em traces) e OpenCensus (traces e métricas, liderado pelo Google). Cada biblioteca de instrumentação precisava escolher um dos dois, fragmentando o ecossistema — uma biblioteca instrumentada para OpenTracing não conversava com um backend pensado para OpenCensus sem camadas de tradução.
Em 2019, os dois projetos se fundiram no OpenTelemetry, sob a CNCF (a mesma fundação que abriga Kubernetes e Prometheus). Isso resolveu a fragmentação e, mais importante, deu ao projeto neutralidade de fornecedor: nenhum vendor de observabilidade controla o padrão, o que fez praticamente todos os grandes players (Datadog, New Relic, Grafana, AWS, Google Cloud, Azure) apoiarem OTLP como protocolo de entrada nativo. Hoje, instrumentar com OpenTelemetry é a opção que menos prende a aplicação a um fornecedor específico.
4. Conceitos de tracing: trace, span e contexto
Retomando e aprofundando o que o artigo 1 introduziu:
- Span — a unidade básica: representa uma operação com início, fim e duração (uma chamada HTTP, uma query, um cálculo). Carrega um nome, atributos (pares chave-valor arbitrários) e, opcionalmente, eventos pontuais dentro do seu intervalo de tempo.
-
Trace — o conjunto de todos os spans gerados para atender uma única requisição de ponta a ponta, conectados entre si por um
trace idcompartilhado. - Span pai/filho — um span pode iniciar outros spans "dentro" dele (por exemplo, o span da requisição HTTP inicia um span filho para a query de banco que ela dispara). Essa relação de aninhamento é o que permite reconstruir a árvore de tempo vista no artigo 1.
-
Propagação de contexto — quando uma requisição atravessa um limite de processo (chamada HTTP entre dois serviços), o
trace ide ospan idatual viajam como cabeçalhos HTTP (o formato padrão é otraceparent, definido pela especificação W3C Trace Context), permitindo que o serviço seguinte continue o mesmo trace em vez de iniciar um novo.
5. Instrumentando a mini app Python
O SDK oficial do Python precisa ser instalado (não é parte da biblioteca padrão, diferente do que as mini apps fizeram até aqui para métricas e logs — gerar spans manualmente sem SDK é possível, mas reimplementar amostragem, contexto e propagação à mão perde o sentido de usar um padrão justamente feito para isso):
pip install opentelemetry-sdk
Instrumentação manual, criando um span por requisição:
# tracing.py
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("python-app")
Integrando no app.py do artigo 2, envolvendo o processamento da requisição em um span:
from tracing import tracer
# dentro do do_GET, no branch que nao eh /metrics
with tracer.start_as_current_span("handle_request") as span:
span.set_attribute("http.path", self.path)
request_count += 1
log_to_loki(f"requisicao recebida em {self.path}")
span.set_attribute("http.status_code", 200)
Por enquanto, o exportador usado é o ConsoleSpanExporter, que apenas imprime cada span no stdout — suficiente para confirmar que a instrumentação está gerando dados, sem depender de nenhuma infraestrutura adicional ainda. Rodando a aplicação e fazendo uma requisição, o terminal deve mostrar um bloco JSON com trace_id, span_id, name e start_time/end_time.
6. Instrumentando a mini app PHP
O equivalente em PHP usa o SDK oficial, instalado via Composer:
composer require open-telemetry/sdk open-telemetry/exporter-otlp
<?php
// tracing.php
require __DIR__ . '/vendor/autoload.php';
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter;
$exporter = new ConsoleSpanExporter();
$tracerProvider = new TracerProvider(
new SimpleSpanProcessor($exporter)
);
$tracer = $tracerProvider->getTracer('php-app');
Integrando no app.php do artigo 3, ao redor do processamento de um pedido:
require __DIR__ . '/tracing.php';
$span = $tracer->spanBuilder('process_order')->startSpan();
$scope = $span->activate();
try {
// ... logica de processamento do pedido, ja existente ...
$span->setAttribute('order.duration_ms', $state['durations'][count($state['durations']) - 1] * 1000);
} finally {
$span->end();
$scope->detach();
}
O padrão try/finally garante que o span é finalizado mesmo se o processamento lançar uma exceção no meio do caminho — um span que nunca termina (por um end() que não é alcançado) é um erro comum de instrumentação manual, e polui o backend de traces com spans "presos".
7. Conclusão e próximos passos
Vimos o que é o OpenTelemetry, por que a fusão de OpenTracing e OpenCensus em 2019 o tornou o padrão neutro de instrumentação, os conceitos de span, trace e propagação de contexto, e instrumentamos manualmente as duas mini apps para gerar spans — por enquanto, só visíveis no console de cada aplicação. No próximo artigo, a stack inteira é unificada em um único docker-compose.yml: as mini apps trocam o ConsoleSpanExporter por um exportador OTLP de verdade, apontando para um coletor OpenTelemetry, ao lado de Prometheus, Loki e Grafana já configurados.
Imagem de capa: Logo oficial do Prometheus — repositório prometheus/prometheus, licença Apache 2.0 (convertido para PNG via wsrv.nl)
Referências:
Top comments (0)