Durable Task Scheduler を使用して OpenTelemetry 分散トレースを有効にする

分散トレースを使用すると、オーケストレーションの実行をエンド ツー エンドで可視化できます。 Durable Task Scheduler で OpenTelemetry を有効にすると、各オーケストレーション、アクティビティ、サブオーケストレーションによって、ワークフロー全体のタイミング、順序、エラーを示すリンクされたスパンが生成されます。 これらのトレースは、Azure Monitor Application InsightsJaeger、または Zipkin など、OpenTelemetry 互換のバックエンドにエクスポートできます。

Durable Functions スタンドアロンの Durable Task SDK はどちらもバックエンドとして Durable Task Scheduler を使用する場合に OpenTelemetry 分散トレースをサポートします。

どのように機能するのか

Durable Task SDK は、OpenTelemetry スパンを使用し、オーケストレーションとアクティビティを自動的にインストルメント化します。 SDK は、各オーケストレーションのために親スパンを作成し、各アクティビティ呼び出し、サブオーケストレーション、タイマーごとに子スパンを作成します。 トレース コンテキストはこれらすべての操作に自動的に伝達されるため、ワークフロー全体に対して 1 つの相関トレースが取得されます。

結果のトレース ツリーは次のようになります。

create_orchestration (client)
  └─ orchestration (server)
       ├─ activity:Step1
       ├─ activity:Step2
       └─ activity:Step3

オーケストレーターまたはアクティビティ コードにカスタム インストルメンテーションを追加する必要はありません。 Microsoft.DurableTask アクティビティ ソースを OpenTelemetry 構成に登録すると、SDK によって残りの処理が行われます。

前提条件

  • Durable Functions 拡張機能 バージョン 2.13.0 以降を含むAzure Functions プロジェクト。
  • 関数アプリのストレージ バックエンドとして構成された Durable Task Scheduler
  • トレースを表示するための OpenTelemetry 互換バックエンド (Application Insights、Jaeger、または別の OTLP コレクター)。
  • .NET 8 SDK 以降。
  • Microsoft.DurableTask.Worker.AzureManagedMicrosoft.DurableTask.Client.AzureManaged NuGet パッケージ。
  • NuGet パッケージの OpenTelemetryOpenTelemetry.Extensions.Hosting、および OpenTelemetry.Exporter.OpenTelemetryProtocol

分散トレースを有効にする

Durable Functionsで分散トレースを有効にするには、host.json を更新し、OpenTelemetry と互換性のあるテレメトリ バックエンドを構成します。

host.json を更新する

host.jsontracingdurableTask の下に セクションを追加します。

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "tracing": {
        "DistributedTracingEnabled": true,
        "Version": "V2"
      }
    }
  }
}

Application Insights の構成

関数アプリで APPLICATIONINSIGHTS_CONNECTION_STRING 環境変数を設定します。

ローカル開発の場合は、 local.settings.jsonに追加します。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "<your-connection-string>"
  }
}

Azureホストされているアプリの場合は、Azure ポータルの Configuration の下にアプリケーション設定として追加します。

以前に APPINSIGHTS_INSTRUMENTATIONKEYを使用していた場合は、最新の機能の APPLICATIONINSIGHTS_CONNECTION_STRING に切り替えます。

テレメトリ のノイズを削減する

Application Insights がトレース データをサンプリングしないようにするには、host.jsonのサンプリング 規則からRequestを除外します。

{
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  }
}

Microsoft.DurableTask アクティビティ ソースを OpenTelemetry 構成に登録します。 Durable Task SDK では、このソースを登録すると、オーケストレーションとアクティビティのスパンが自動的に作成されます。

ワーカーの Program.csで、Durable Task アクティビティ ソースを使用して OpenTelemetry トレースを追加します。

using Microsoft.DurableTask;
using Microsoft.DurableTask.Worker;
using Microsoft.DurableTask.Worker.AzureManaged;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = Host.CreateApplicationBuilder(args);

// Configure OpenTelemetry tracing
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri(
                    Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")
                    ?? "http://localhost:4317");
            });
    });

// Build connection string from environment variables
string endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? "http://localhost:8080";
string taskHub = Environment.GetEnvironmentVariable("TASKHUB") ?? "default";
string connectionString = endpoint.Contains("localhost")
    ? $"Endpoint={endpoint};TaskHub={taskHub};Authentication=None"
    : $"Endpoint={endpoint};TaskHub={taskHub};Authentication=DefaultAzure";

// Configure Durable Task worker
builder.Services.AddDurableTaskWorker()
    .AddTasks(tasks =>
    {
        tasks.AddOrchestratorFunc<string, string>(
            "OrderProcessingOrchestration", async (ctx, input) =>
        {
            var validated = await ctx.CallActivityAsync<string>("ValidateOrder", input);
            var payment = await ctx.CallActivityAsync<string>("ProcessPayment", validated);
            var shipment = await ctx.CallActivityAsync<string>("ShipOrder", payment);
            var result = await ctx.CallActivityAsync<string>("SendNotification", shipment);
            return result;
        });

        tasks.AddActivityFunc<string, string>("ValidateOrder", (ctx, input) =>
            Task.FromResult($"Validated({input})"));
        tasks.AddActivityFunc<string, string>("ProcessPayment", (ctx, input) =>
            Task.FromResult($"Paid({input})"));
        tasks.AddActivityFunc<string, string>("ShipOrder", (ctx, input) =>
            Task.FromResult($"Shipped({input})"));
        tasks.AddActivityFunc<string, string>("SendNotification", (ctx, input) =>
            Task.FromResult($"Notified({input})"));
    })
    .UseDurableTaskScheduler(connectionString);

var host = builder.Build();
await host.RunAsync();

重要な行は .AddSource("Microsoft.DurableTask")であり、Durable Task SDK が出力するスパンをキャプチャするように OpenTelemetry に指示します。

OTLP エンドポイントを構成する

上記のコード スニペットは、 OTEL_EXPORTER_OTLP_ENDPOINT 環境変数を参照して、トレース データの宛先を設定します。 バックエンドに基づいてこの変数を設定します。

Backend エンドポイント値 プロトコル
Jaeger (ローカル) http://localhost:4317 gRPC
Jaeger (ローカル、HTTP) http://localhost:4318 HTTP/protobuf
OpenTelemetry コレクター http://<collector-host>:4317 gRPC
Azure Monitor (OTLP 経由) 代わりに Azure Monitor エクスポーターを使用する N/A

Jaeger を使用したローカル開発では、Jaeger が OTLP gRPC を有効 (ポート 4317) で実行している場合、既定の http://localhost:4317 が機能します。 JavaScript SDK は既定で HTTP/protobuf を使用するため、4318 パスを持つポート /v1/tracesを対象とします。

Jaeger UI を使用してトレースをローカルで表示する

ローカル開発の場合は、JaegerDurable Task Scheduler エミュレーターを使用してトレースを表示します。 両方のサービスを開始するには、 docker-compose.yml を使用します。

services:
  dts-emulator:
    image: mcr.microsoft.com/dts/dts-emulator:latest
    ports:
      - "8080:8080"  # gRPC
      - "8082:8082"  # Dashboard
  jaeger:
    image: jaegertracing/jaeger:latest
    ports:
      - "16686:16686"  # Jaeger UI
      - "4317:4317"    # OTLP gRPC
      - "4318:4318"    # OTLP HTTP

インフラストラクチャを開始します。

docker compose up -d

アプリケーションを実行したら、 http://localhost:16686 で Jaeger UI を開き、サービス名 ( durable-worker など) を検索してトレースを表示します。

Durable Functionsを使用したローカル開発の場合、分散トレース データは既定で Application Insights に送信されます。 デプロイせずにトレースをローカルで表示するには、関数アプリの Program.csに Application Insights と共に OTLP エクスポーターを追加します。

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri("http://localhost:4317");
            });
    });

次に、 docker run -d -p 16686:16686 -p 4317:4317 jaegertracing/jaeger:latest を使用して Jaeger をローカルで実行し、 http://localhost:16686で Jaeger UI を開きます。

Application Insights でトレースを表示する

運用環境のワークロードでは、 Application Insights が推奨されるテレメトリ バックエンドです。

DistributedTracingEnabled の中で trueVersion に設定され、V2host.json に設定された後、開発中の Durable Functions アプリは、Application Insights に関連付けられたスパンを出力します。 Azure ポータルで完全なオーケストレーション トレースを表示するには:

  1. Azure ポータルで Application Insights リソースに移動します。
  2. トランザクション検索を開き、名前またはインスタンス ID でオーケストレーションを検索します。
  3. トレースを選択すると、すべての相関スパンを持つエンドツーエンドのトランザクションが表示されます。

トレースは、各アクティビティ呼び出し、サブオーケストレーション、タイマー待機ごとに、子スパンを持つ親スパンという形でオーケストレーションを表示します。 次のパターンでは、個別のトレース図形が生成されます。

パターン トレース図形
関数の連鎖 オーケストレーター スパンの下で入れ子になっている複数のシーケンシャル アクティビティ スパン。
ファンアウト/ファンイン 並列アクティビティ スパンは、時間方向で重なり合っています。
人間との相互作用 外部イベントを長時間待機するオーケストレーター スパン。
モニター 反復アクティビティは、イテレーションの間にタイマー待ちを伴って繰り返し実行されます。

Azure Monitor OpenTelemetry エクスポーターを使用して Application Insights にトレースを送信するように OTLP エクスポーターを構成するか、OTLP を介して Application Insights に転送する OpenTelemetry コレクターにエクスポートします。

Azure.Monitor.OpenTelemetry.Exporter NuGet パッケージをインストールし、OTLP エクスポーターを次のように置き換えます。

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddAzureMonitorTraceExporter(opts =>
            {
                opts.ConnectionString = Environment.GetEnvironmentVariable(
                    "APPLICATIONINSIGHTS_CONNECTION_STRING");
            });
    });

トレース データに表示される内容

Durable Task SDK によって生成されるトレース データには、次のものが含まれます。

スパンの種類 説明
create_orchestration 新しいオーケストレーションをスケジュール設定するときに出力されるクライアント側のスパン
orchestration 完全な実行ライフサイクルをカバーするサーバー側オーケストレーションスパン
activity:<name> タイミングと結果を示す各アクティビティ呼び出しのスパン
sub_orchestration:<name> 各サブオーケストレーション呼び出しのスパン
timer 永続タイマーの待機に対応するスパン

各スパンには、 durabletask.typedurabletask.task.namedurabletask.task.instance_iddurabletask.task.task_idなどの属性が含まれます。 失敗したアクティビティとオーケストレーションは、スパンの状態やイベントの中で、エラーの詳細を保持しています。

Troubleshooting

問題点 Resolution
痕跡が表示されない Microsoft.DurableTask アクティビティ ソースが登録され、エクスポーター エンドポイントに到達可能であることを確認します。
トレースが不完全です Durable Task SDK (特に JavaScript/TypeScript) の 前に OpenTelemetry SDK が初期化されていることを確認します。
Application Insights の中で不足しているスパン トレース データが削除されないように、 サンプリング設定 を無効または調整します。
トレースは一致しません バックエンドとして Durable Task Scheduler を使用していることを確認します。 トレース コンテキストの伝達にはスケジューラが必要です。

サンプル コード