Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第2章 単純構成:OpenTelemetry SDK と Jaeger v2 によるトレース構築

本章では、OpenTelemetry SDK から分散トレーシングシステム「Jaeger v2」へ直接トレースデータを送信する最小構成を構築します。中間サーバー(Collector)を挟まず、手元の開発マシンで手軽に動作確認できる手順を解説します。

アーキテクチャの概要

最小構成のデータフローは以下の通りです。

+-----------------------+
|  Python アプリケーション |
|  (OpenTelemetry SDK)  |----+
+-----------------------+    |
                             | OTLP (gRPC: 4317 / HTTP: 4318)
+-----------------------+    |
|   C# アプリケーション  |----+
|  (OpenTelemetry SDK)  |    |
+-----------------------+    v
                    +--------------------+
                    |     Jaeger v2      |
                    |  - OTLP Receiver   |
                    |  - UI (:16686)     |
                    +--------------------+

Jaeger v2 は、OpenTelemetry Collector のフレームワークを基盤として再構築された新世代の Jaeger です。従来の独自プロトコル(Thrift など)に代わり、OTLP(ポート 4317 / 4318)を第一級の受信口として標準サポートしています。

Jaeger v2 の起動(Docker Compose)

作業用ディレクトリを用意し、Jaeger v2 を起動するための docker-compose.yaml を作成します。

services:
  jaeger:
    image: jaegertracing/jaeger:2.3.0
    container_name: jaeger-v2
    ports:
      - "16686:16686" # Jaeger UI
      - "4317:4317"   # OTLP gRPC 受信ポート
      - "4318:4318"   # OTLP HTTP 受信ポート
    environment:
      - METRICS_STORAGE_TYPE=memory

以下のコマンドを実行してコンテナを起動します。

docker compose up -d

起動後、ブラウザで http://localhost:16686 にアクセスすると、Jaeger の Web UI が表示されます。

Python によるトレース送信実装

Python の OpenTelemetry SDK を使用し、Jaeger へトレースを直接送信するコードを作成します。

必要なパッケージのインストール

仮想環境を作成し、必要なライブラリをインストールします。

pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp

送信スクリプト(trace_sample.py)

以下のスクリプトは、親スパン(Parent Span)と子スパン(Child Span)を作成し、属性(Attributes)やイベントを付加して送信します。

import time
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# 1. サービス名などのリソース情報を定義
resource = Resource.create(
    attributes={
        "service.name": "order-service-python",
        "service.version": "1.0.0",
        "deployment.environment": "development",
    }
)

# 2. TracerProvider を作成し、OTLP エクスポーターを登録
provider = TracerProvider(resource=resource)
# Jaeger v2 の gRPC エンドポイント (localhost:4317) を指定
processor = BatchSpanProcessor(
    OTLPSpanExporter(endpoint="localhost:4317", insecure=True)
)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 3. トレーサーを取得
tracer = trace.get_tracer("order-service-tracer")


def process_order(order_id: str):
    # 親スパンの開始
    with tracer.start_as_current_span("create_order") as parent_span:
        parent_span.set_attribute("order.id", order_id)
        parent_span.set_attribute("customer.vip", True)
        time.sleep(0.1)

        # 子スパンの開始
        with tracer.start_as_current_span("validate_inventory") as child_span:
            child_span.set_attribute("item.sku", "ITEM-9981")
            child_span.set_attribute("item.quantity", 2)
            time.sleep(0.05)
            child_span.add_event("在庫の引き当てに成功しました")

        with tracer.start_as_current_span("charge_payment") as child_span:
            child_span.set_attribute("payment.method", "credit_card")
            child_span.set_attribute("payment.amount", 3500)
            time.sleep(0.08)

    print(f"注文処理が完了しました: {order_id}")


if __name__ == "__main__":
    process_order("ORD-2026-001")
    # バッファされたスパンを確実にフラッシュして終了
    provider.shutdown()

スクリプトの実行

python trace_sample.py

C# によるトレース送信実装

.NET では、ランタイム組み込みの System.Diagnostics.ActivitySource と OpenTelemetry .NET SDK を組み合わせてトレースを送信します。

プロジェクトの作成とパッケージ追加

.NET 8 または .NET 10 を想定したコンソールアプリケーションを作成します。

dotnet new console -n OtelSampleCSharp
cd OtelSampleCSharp
dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

送信プログラム(Program.cs)

Program.cs を以下のように記述します。

using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

const string serviceName = "payment-service-csharp";
const string serviceVersion = "1.0.0";

// 1. .NET 組み込みの ActivitySource を定義
var activitySource = new ActivitySource(serviceName, serviceVersion);

// 2. OpenTelemetry TracerProvider を構築
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .ConfigureResource(resource => resource.AddService(
        serviceName: serviceName,
        serviceVersion: serviceVersion,
        serviceInstanceId: Environment.MachineName))
    .AddSource(serviceName)
    // Jaeger v2 の gRPC エンドポイント (http://localhost:4317) を指定
    .AddOtlpExporter(options =>
    {
        options.Endpoint = new Uri("http://localhost:4317");
        options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
    })
    .Build();

// 3. 業務処理を実行し、スパン(Activity)を生成
ProcessPayment("PAY-2026-8871", 5200);

void ProcessPayment(string paymentId, decimal amount)
{
    // 親スパンの開始
    using (var parentActivity = activitySource.StartActivity("ProcessPayment"))
    {
        parentActivity?.SetTag("payment.id", paymentId);
        parentActivity?.SetTag("payment.amount", amount);
        Thread.Sleep(100);

        // 子スパンの開始
        using (var authActivity = activitySource.StartActivity("AuthorizeCard"))
        {
            authActivity?.SetTag("card.brand", "Visa");
            Thread.Sleep(60);
            authActivity?.AddEvent(new ActivityEvent("カード与信枠を確保しました"));
        }

        using (var settleActivity = activitySource.StartActivity("SettleTransaction"))
        {
            settleActivity?.SetTag("settlement.currency", "JPY");
            Thread.Sleep(80);
        }
    }

    Console.WriteLine($"決済処理が完了しました: {paymentId}");
}

プログラムの実行

dotnet run

Jaeger UI でのトレース確認

  1. ブラウザで http://localhost:16686 を開きます。
  2. 左メニューの Service ドロップダウンをクリックします。
  3. order-service-python または payment-service-csharp が表示されていることを確認し、選択します。
  4. Find Traces ボタンをクリックします。
  5. 検索結果一覧からトレースをクリックすると、タイムライン形式で各スパンの親子関係、実行所要時間、付与した属性(Tags)やイベントが表示されます。