1. Retomando: as peças soltas até aqui
Cada artigo desta série subiu uma peça isolada: Prometheus + Loki + Grafana no artigo 1, a mini app Python no artigo 2, a mini app PHP no artigo 3, envio de logs para o Loki no artigo 4, e instrumentação de traces (por enquanto só impressos no console) no artigo 5. Este artigo une tudo em um único docker-compose.yml, com uma peça nova: um coletor OpenTelemetry, responsável por receber os traces das mini apps via OTLP e encaminhá-los adiante.
2. Por que um coletor no meio do caminho
No artigo 5, as mini apps exportavam spans diretamente para o console (ConsoleSpanExporter). Isso prova que a instrumentação funciona, mas não é assim que uma aplicação real se comunica com uma stack de observabilidade — cada aplicação teria que saber exportar diretamente para cada backend final, duplicando configuração de endpoint, autenticação e formato em todas elas.
O OpenTelemetry Collector resolve isso ficando no meio: as aplicações exportam sempre para o mesmo lugar (o coletor, via OTLP), e é o coletor — configurado uma vez, centralmente — quem decide para onde os dados seguem depois: um backend de traces, processamento adicional (amostragem, enriquecimento de atributos), ou múltiplos destinos ao mesmo tempo. Trocar de backend passa a ser uma mudança de configuração do coletor, não um redeploy de cada aplicação instrumentada.
3. Trocando o exportador de console por OTLP
Nas duas mini apps, o único ponto que muda em relação ao artigo 5 é o exportador — a forma como os spans saem do processo — não a instrumentação em si (os tracer.start_as_current_span e spanBuilder(...)->startSpan() continuam idênticos).
# tracing.py (Python) — troca do ConsoleSpanExporter por OTLP
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
OTLPSpanExporter,
)
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="http://otel-collector:4318/v1/traces")
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("python-app")
pip install opentelemetry-exporter-otlp-proto-http
<?php
// tracing.php (PHP) — troca do ConsoleSpanExporter por OTLP
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Transport\Http\PsrTransportFactory;
$transport = (new PsrTransportFactory())->create(
'http://otel-collector:4318/v1/traces',
'application/x-protobuf'
);
$exporter = new SpanExporter($transport);
$tracerProvider = new TracerProvider(new SimpleSpanProcessor($exporter));
$tracer = $tracerProvider->getTracer('php-app');
O hostname otel-collector usado nos dois casos é o nome do serviço do Compose que aparece na seção 5.
4. Configurando o coletor
O coletor precisa de um arquivo de configuração declarando três coisas: receivers (como os dados entram), processors (transformações opcionais no meio do caminho) e exporters (para onde os dados saem):
# otel-collector-config.yaml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
processors:
batch:
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [debug]
Este exemplo usa o exportador debug (o sucessor do antigo logging exporter), que imprime os traces recebidos no log do próprio coletor — suficiente para confirmar que o pipeline completo funciona de ponta a ponta: mini app → coletor → saída. Visualizar traces de forma gráfica, com uma árvore de spans navegável, exigiria um backend de tracing dedicado (como Grafana Tempo ou Jaeger) recebendo esse mesmo exportador — fora do escopo desta stack mínima, mas um próximo passo natural para quem quiser aprofundar depois desta série.
5. O docker-compose.yml unificado
Juntando tudo o que a série construiu até aqui em um único arquivo:
# docker-compose.yml
services:
prometheus:
image: prom/prometheus:v2.55.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
loki:
image: grafana/loki:3.2.0
ports:
- "3100:3100"
otel-collector:
image: otel/opentelemetry-collector:0.112.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
ports:
- "4318:4318"
grafana:
image: grafana/grafana:11.3.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
depends_on:
- prometheus
- loki
python-app:
image: python:3.12-slim
working_dir: /app
volumes:
- ./python-app:/app:ro
command: ["sh", "-c", "pip install --no-cache-dir opentelemetry-sdk opentelemetry-exporter-otlp-proto-http && python3 app.py"]
ports:
- "8000:8000"
depends_on:
- otel-collector
- loki
php-app:
image: php:8.3-cli
working_dir: /app
volumes:
- ./php-app:/app
command: ["php", "-S", "0.0.0.0:8001", "app.php"]
ports:
- "8001:8001"
depends_on:
- otel-collector
- loki
E o prometheus.yml reunindo os alvos dos artigos 2 e 3:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
- job_name: "python-app"
static_configs:
- targets: ["python-app:8000"]
- job_name: "php-app"
static_configs:
- targets: ["php-app:8001"]
Subindo tudo de uma vez:
docker compose up -d
docker compose ps
Seis serviços devem aparecer no ar: prometheus, loki, otel-collector, grafana, python-app e php-app.
6. Configurando os datasources no Grafana
Com todos os serviços na mesma rede do Compose, em Connections → Data sources no Grafana, dois datasources apontam para os serviços pelo nome:
-
Prometheus —
http://prometheus:9090 -
Loki —
http://loki:3100
Esses são os dois datasources que o artigo 7 desta série vai efetivamente usar em dashboards. O coletor OpenTelemetry não aparece como datasource do Grafana neste setup — ele só encaminha traces para o exportador debug configurado na seção 4; ligar um datasource de traces é o passo seguinte caso um backend de tracing seja adicionado à stack.
7. Confirmando que o pipeline completo funciona
Gerando tráfego nas duas aplicações e conferindo cada ponta:
curl http://localhost:8000/
curl http://localhost:8001/
# metricas
curl http://localhost:8000/metrics
curl http://localhost:8001/metrics
# logs do coletor, onde os traces devem aparecer impressos
docker compose logs otel-collector --tail 50
Se o docker compose logs otel-collector mostrar blocos com TraceID, SpanID e Name para as requisições feitas, o pipeline de ponta a ponta está funcionando: as mini apps geram spans, o coletor os recebe via OTLP e os processa.
8. Conclusão e próximos passos
Unimos as seis peças construídas ao longo da série em uma stack única e reproduzível: duas mini aplicações instrumentadas para métricas, logs e traces, Prometheus fazendo scraping, Loki recebendo logs, um coletor OpenTelemetry recebendo traces via OTLP, e Grafana com os datasources de Prometheus e Loki configurados. No próximo artigo, o foco volta para o Grafana: construir dashboards reais que combinam PromQL e LogQL para acompanhar as mini apps de ponta a ponta em um único painel.
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)