エンドツーエンドで動かす
🐱 この章の目次
構成の全体像
本章では、FastAPI アプリに OTel SDK を組み込み、Collector 経由で Jaeger・Prometheus・Grafana へデータを送る一気通貫の環境を構築します。 すべてのコンポーネントを Docker Compose で起動し、リクエストがトレースされる様子をブラウザで確認します。
| コンポーネント | ポート | 役割 |
|---|---|---|
| FastAPI アプリ | 8000 | 計装対象のサービス |
| OTel Collector | 4317 | テレメトリーの中継 |
| Jaeger UI | 16686 | トレースの可視化 |
| Prometheus | 9090 | メトリクスの収集 |
| Grafana | 3000 | ダッシュボード |
Docker Compose
services:
app:
build: .
ports:
- "8000:8000"
environment:
OTEL_SERVICE_NAME: demo-app
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
depends_on:
- otel-collector
otel-collector:
image: otel/opentelemetry-collector-contrib:0.104.0
command: ["--config", "/etc/otel/config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel/config.yaml
ports:
- "4317:4317"
- "8889:8889"
jaeger:
image: jaegertracing/all-in-one:1.58
ports:
- "16686:16686"
- "4317"
prometheus:
image: prom/prometheus:v2.53.0
volumes:
- ./prometheus.yaml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:11.1.0
ports:
- "3000:3000"
environment:
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
アプリケーションの計装コード
FastAPI アプリに 3 シグナルすべてを組み込んだエントリーポイントの例です。
import logging
import time
from fastapi import FastAPI
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
from opentelemetry._logs import set_logger_provider
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
# Traces
trace_provider = TracerProvider()
trace_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(trace_provider)
# Metrics
metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter())
metrics.set_meter_provider(MeterProvider(metric_readers=[metric_reader]))
# Logs
log_provider = LoggerProvider()
log_provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter()))
set_logger_provider(log_provider)
logging.getLogger().addHandler(LoggingHandler(level=logging.INFO, logger_provider=log_provider))
app = FastAPI()
FastAPIInstrumentor.instrument_app(app)
logger = logging.getLogger(__name__)
tracer = trace.get_tracer(__name__)
meter = metrics.get_meter(__name__)
request_counter = meter.create_counter("app.requests", unit="1")
@app.get("/orders/{order_id}")
async def get_order(order_id: str):
request_counter.add(1, {"endpoint": "/orders"})
with tracer.start_as_current_span("fetch-order") as span:
span.set_attribute("order.id", order_id)
logger.info(f"Fetching order {order_id}")
await simulate_latency()
return {"order_id": order_id, "status": "shipped"}
async def simulate_latency():
"""意図的に遅延を入れてトレースで確認する"""
time.sleep(0.3)
トレースの確認
環境を起動してリクエストを送信します。
docker compose up -d
curl http://localhost:8000/orders/abc-123
ブラウザで http://localhost:16686 を開き、Jaeger UI から demo-app サービスを選択してください。
GET /orders/{order_id} の Span とその子 Span fetch-order が表示され、処理時間の内訳を確認できます。
レイテンシ問題のデバッグ
simulate_latency が 300ms のスリープを挿入しているため、Jaeger のトレースで fetch-order Span に遅延が集中していることが分かります。
Prometheus で app.requests カウンターの増加を確認し、Grafana ダッシュボードでレイテンシの傾向を可視化しましょう。
トレース・メトリクス・ログを横断的に分析することで、問題の特定から原因の深掘りまでを効率的に進められます。