Do primeiro pip install ao painel no Grafana: o caminho completo para instrumentar um serviço com o padrão aberto que dominou a observabilidade.
Toda equipe de engenharia conhece a cena: o sistema degrada, o alerta dispara (ou pior, o cliente reclama primeiro) e começa a caçada. Alguém abre o log do serviço A, outra pessoa o do serviço B, e a pergunta que importa — onde, exatamente, essa requisição quebrou? — segue sem resposta, porque cada log conta uma história isolada.
Este guia mostra o caminho prático para sair desse cenário usando a stack open source que virou padrão de mercado: OpenTelemetry para instrumentar, Collector para processar e Grafana para visualizar. Ao final, você terá um serviço Python emitindo traces e métricas, um pipeline de telemetria configurado e um dashboard funcionando — além das armadilhas mais comuns já sinalizadas para você não cair nelas.
Logs são a forma mais antiga e mais usada de telemetria — e continuam necessários. O problema não é o log em si: é o log desconectado. Em uma arquitetura distribuída, uma única ação do usuário atravessa gateway, serviços, filas e bancos. Quando cada componente registra eventos por conta própria, sem um identificador comum, reconstruir a jornada de uma requisição vira arqueologia.
Os sintomas são conhecidos. O tempo de diagnóstico de incidente cresce à medida que a arquitetura cresce. Perguntas simples — "por que o p99 dobrou às 14h?" — exigem correlacionar manualmente fontes que não se conhecem. E o volume de log (com o custo de armazená-lo) sobe sem que a capacidade de resposta suba junto.
Observabilidade é a propriedade que falta: a capacidade de entender o estado interno do sistema a partir do que ele emite. E ela não nasce de mais logs — nasce de telemetria correlacionada: o trace conecta a jornada, a métrica dá a tendência, o log guarda o detalhe. É esse tripé que o OpenTelemetry padroniza.
OpenTelemetry (OTel) é um projeto open source da CNCF — a mesma fundação do Kubernetes — que define um padrão único para gerar, coletar e exportar telemetria: APIs, SDKs por linguagem, um protocolo de transporte (OTLP) e um componente de pipeline (o Collector). Nasceu em 2019 da fusão dos projetos OpenTracing e OpenCensus e é hoje um dos projetos mais ativos da fundação, atrás apenas do próprio Kubernetes.
A razão da adoção massiva é estratégica, não técnica: fim do lock-in de instrumentação. Antes do OTel, instrumentar o código significava usar o agente proprietário do fornecedor da vez — e trocar de fornecedor significava reinstrumentar tudo. Com OTel, o código emite telemetria em formato neutro, e o destino (Grafana, Datadog, New Relic, Jaeger, qualquer backend compatível) vira decisão de configuração, tomada fora do código. Praticamente todos os grandes fornecedores de observabilidade aceitam OTLP nativamente.
Para o engenheiro, a consequência prática é uma só: instrumentar com OTel é um investimento que sobrevive a qualquer troca de ferramenta.
Traces respondem "por onde a requisição passou e onde gastou tempo". Um trace é a jornada completa de uma requisição, composta de spans — cada span é uma operação (uma chamada HTTP, uma query, um processamento) com início, duração, atributos e relação de pai/filho. É o pilar que resolve o problema do capítulo 1, porque o trace_id viaja entre os serviços via propagação de contexto.
Métricas respondem "como o sistema se comporta ao longo do tempo". São agregações numéricas — contadores, histogramas, gauges — baratas de armazenar e ideais para dashboards e alertas: taxa de requisições, taxa de erro, latência por percentil.
Logs respondem "o que exatamente aconteceu naquele ponto". No OTel, o log deixa de ser texto solto: ele carrega o trace_id da requisição em que ocorreu. É essa correlação que transforma o log de ruído em evidência: do gráfico anômalo você chega ao trace, do span lento você chega ao log daquele exato momento.
Vamos instrumentar um serviço FastAPI — o cenário se aplica igualmente a Flask, Django ou qualquer framework popular, porque o OTel oferece instrumentação automática para as bibliotecas mais usadas. Primeiro, as dependências:
bashpip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
O comando opentelemetry-bootstrap detecta as bibliotecas do seu ambiente (FastAPI, requests, SQLAlchemy, psycopg2…) e instala a instrumentação correspondente. Com isso, dá para começar sem alterar uma linha de código, via auto-instrumentação:
OTEL_SERVICE_NAME=pedidos-api \
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
OTEL_TRACES_EXPORTER=otlp OTEL_METRICS_EXPORTER=otlp \
opentelemetry-instrument uvicorn app:app --host 0.0.0.0 --port 8000
Só isso já gera spans para cada requisição HTTP recebida, cada chamada externa e cada query — com propagação de contexto entre serviços incluída. Para enriquecer os traces com o vocabulário do seu domínio, adicione spans manuais nos pontos de negócio importantes:
python · app.pyfrom opentelemetry import trace
tracer = trace.get_tracer("pedidos-api")
@app.post("/checkout")
async def checkout(pedido: Pedido):
with tracer.start_as_current_span("calcular_frete") as span:
span.set_attribute("pedido.itens", len(pedido.itens))
span.set_attribute("pedido.uf", pedido.uf)
frete = calcular_frete(pedido) # aparece como span filho no trace
return {"frete": frete}
Dá para exportar telemetria direto da aplicação para o backend — mas em qualquer cenário real, o OpenTelemetry Collector no meio do caminho é a arquitetura certa. Ele é um processo independente que recebe, processa e encaminha telemetria, e resolve três problemas de uma vez: tira da aplicação a responsabilidade (e o custo de CPU) de processar telemetria, centraliza credenciais e destinos em um lugar só, e permite filtrar, amostrar e enriquecer dados antes de pagar para armazená-los.
A configuração é um YAML com quatro blocos: receivers (por onde entra), processors (o que acontece no meio), exporters (para onde vai) e service.pipelines (a ligação entre eles):
receivers:
otlp:
protocols:
grpc: { endpoint: 0.0.0.0:4317 }
http: { endpoint: 0.0.0.0:4318 }
processors:
batch: # agrupa envios — sempre use
timeout: 5s
memory_limiter: # protege o collector de OOM
check_interval: 1s
limit_percentage: 80
resource:
attributes:
- { key: deployment.environment, value: production, action: upsert }
exporters:
otlp/tempo: # traces → Grafana Tempo
endpoint: tempo:4317
tls: { insecure: true }
prometheusremotewrite: # métricas → Prometheus/Mimir
endpoint: http://prometheus:9090/api/v1/write
loki: # logs → Grafana Loki
endpoint: http://loki:3100/loki/api/v1/push
service:
pipelines:
traces: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlp/tempo] }
metrics: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [prometheusremotewrite] }
logs: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [loki] }
Suba o Collector como container ao lado dos serviços (ou como DaemonSet/sidecar no Kubernetes) e aponte o OTEL_EXPORTER_OTLP_ENDPOINT de todas as aplicações para ele. A partir daqui, qualquer mudança de backend é uma edição neste YAML — o código não sabe e não precisa saber.
Com a telemetria fluindo, falta a camada de visualização. Na stack open source, o arranjo padrão é: Tempo armazena traces, Prometheus (ou Mimir) armazena métricas, Loki armazena logs, e o Grafana consulta os três. No Grafana, cadastre cada um em Connections → Data sources, apontando para os endpoints dos serviços.
O primeiro dashboard que vale construir é o de golden signals do serviço — quatro painéis, todos alimentados pelas métricas que a auto-instrumentação já emite:
rate(http_server_duration_count[5m])histogram_quantile(0.95, ...) sobre o histograma de duraçãoA mágica aparece na correlação: configurando o trace to logs e o exemplars nos data sources, o Grafana permite clicar em um ponto anômalo do gráfico de latência e abrir o trace exato daquela requisição — e, do span, pular para os logs daquele instante. O tripé do capítulo 3, funcionando na prática, em uma única ferramenta.
service.name, http.route…). Telemetria com nomes inconsistentes entre serviços não correlaciona.service.name e deployment.environment em tudo. São os dois atributos que separam o dashboard útil do caos.batch e o memory_limiter sempre. Collector sem eles cai exatamente no pior momento: durante o pico de tráfego que você queria observar.O caminho percorrido — SDK, Collector, Grafana — coloca um time em condição de responder em minutos o que antes levava horas. Os próximos degraus naturais: expandir a instrumentação para os demais serviços, adotar tail-based sampling para controlar custo com inteligência, levar SLOs para os dashboards e conectar alertas ao fluxo de incidente do time.
O degrau menos óbvio — e mais determinante — é o organizacional: observabilidade boa é a que o time inteiro usa. Dashboard que só uma pessoa entende é o novo log solto.
A FuncCloud desenha e implementa stacks de observabilidade e plataformas internas que dão ao time de engenharia visibilidade e autonomia — do diagnóstico à operação.
Falar com a FuncCloud →