次の方法で共有


System.Net ライブラリでの分散トレース

分散トレース は、エンジニアがアプリケーション内の障害とパフォーマンスの問題 (特に複数のマシンまたはプロセスに分散されているもの) をローカライズするのに役立つ診断手法です。 この手法では、異なるコンポーネントによって実行される作業を相互に関連付け、アプリケーションが同時要求に対して実行している可能性がある他の作業からそれを分離することによって、アプリケーションを介して要求を追跡します。 たとえば、一般的な Web サービスへの要求は、最初にロード バランサーによって受信され、次に Web サーバー プロセスに転送され、データベースに対して複数のクエリが実行される場合があります。 分散トレースを使用すると、エンジニアは、これらのステップのいずれかが失敗したかどうかと、各ステップにかかった時間を区別できます。 また、各ステップで生成されたメッセージを、実行時にログに記録することもできます。

.NET のトレース システムは、OpenTelemetry (OTel) と連携するように設計されており、OTel を使用して監視システムにデータをエクスポートします。 .NET でのトレースは、System.Diagnostics API を使用して実装されます。この API では、System.Diagnostics.Activity クラスによって作業単位が表されます。これは、OTel スパンに対応します。 OpenTelemetry では、スパン (アクティビティ) の業界標準の名前付けスキームと、セマンティック規則と呼ばれる属性 (タグ) を定義します。 .NET テレメトリでは、可能な限り既存のセマンティック規則が使用されます。

手記

この記事では、"スパン" という用語と "アクティビティ" という用語は同義語です。 .NET コードのコンテキストでは、System.Diagnostics.Activity インスタンスを参照します。 OTel スパンを System.Span<T>と混同しないでください。

ヒント

すべての組み込みアクティビティとそのタグ/属性の包括的な一覧については、「.NET の組み込みアクティビティ参照してください。

インストルメンテーション

トレースを出力するために、System.Net ライブラリは組み込みの ActivitySource ソースを使用して インストルメント化 され、実行された作業を追跡する Activity オブジェクトが作成されます。 アクティビティは、ActivitySourceにサブスクライブされているリスナーがある場合にのみ作成されます。

組み込みのインストルメンテーションは.NET バージョンで進化しました。

System.Net トレースを収集する

最下位レベルのでは、ユーザー定義ロジックを含むオブジェクト ActivityListener 登録する AddActivityListener メソッドを使用してトレースコレクションがサポートされます。

ただし、アプリケーション開発者は、OpenTelemetry .NET SDK によって提供される機能に基づいて構築された豊富なエコシステムに依存して、トレースの収集、エクスポート、監視を行う方が望ましいでしょう。

  • OTel を使用したトレース収集に関する基本的な理解を得るには、OpenTelemetry を使用してトレースを収集するに関するガイドを参照してください。
  • 運用時のトレース収集と監視には、OpenTelemetry を Prometheus、Grafana、Jaeger と共に、または Azure Monitor および Application Insights と共に使用できます。 ただし、これらのツールは非常に複雑であり、開発時に使用するのが不便な場合があります。
  • 開発時のトレース収集と監視には、アプリケーションで分散トレースを開始し、ローカルで問題を診断するためのシンプルかつ拡張可能な方法を提供する .NET Aspire の使用をお勧めします。
  • また、アスパイア オーケストレーションなしで、サービスの既定値 プロジェクトを再利用することもできます。 これは、ASP.NET プロジェクトで OpenTelemetry のトレースとメトリックを導入して構成する便利な方法です。

.NET のアスパイアを使用してトレースを収集する

ASP.NET アプリケーションでトレースとメトリックを収集する簡単な方法は、.NET Aspireを使用することです。 .NET Aspire は、分散アプリケーションを簡単に作成して操作できるようにするための .NET の拡張機能のセットです。 .NET Aspire を使用する利点の 1 つは、.NET 用の OpenTelemetry ライブラリを使用してテレメトリが組み込まれている点です。

.NET Aspire の既定のプロジェクト テンプレートには、ServiceDefaults プロジェクトが含まれています。 .NET アスパイア ソリューション内の各サービスには、サービスの既定値プロジェクトへの参照があります。 サービスはそれを使用して OTel を設定および構成します。

Service Defaults プロジェクト テンプレートには、OTel SDK、ASP.NET、HttpClient、ランタイム インストルメンテーション パッケージが含まれています。 これらのインストルメンテーション コンポーネントは、Extensions.cs ファイルで構成されます。 アスパイア ダッシュボードでのテレメトリの視覚化をサポートするために、Service Defaults プロジェクトには既定で OTLP エクスポーターも含まれています。

アスパイア ダッシュボードは、テレメトリの監視をローカル デバッグ サイクルに取り込むよう設計されています。これにより、開発者はアプリケーションがテレメトリを生成していることを確認できます。 テレメトリの視覚化は、これらのアプリケーションをローカルで診断するのにも役立ちます。 サービス間の呼び出しを監視できることは、運用環境と同じようにデバッグ時に役立ちます。 .NET Aspire ダッシュボードは、Visual Studio から AppHost プロジェクトに対して F5 を実行するか、コマンド ラインから AppHost プロジェクトに対して dotnet run を実行すると自動的に起動します。

アスパイア ダッシュボード

.NET Aspire の詳細については、次を参照してください。

.NET のアスパイア オーケストレーションを使用せずにサービスの既定のプロジェクトを再利用する

アスパイア サービスの既定値プロジェクトは、オーケストレーションに AppHost などの .NET アスパイア の残りの部分を使用しない場合でも、ASP.NET プロジェクト用に OTel を構成する簡単な方法を提供します。 Service Defaults プロジェクトは、Visual Studio または dotnet newを使用してプロジェクト テンプレートとして使用できます。 OTel を構成し、OTLP エクスポーターを設定します。 その後、OTel 環境変数 を使用して、テレメトリを送信するように OTLP エンドポイントを構成し、アプリケーションのリソース プロパティを指定できます。

.NET Aspire の外部 ServiceDefaults を使用する手順は次のとおりです。

  1. Visual Studio で [新しいプロジェクトの追加] を使用して、ServiceDefaults プロジェクトをソリューションに追加するか、dotnet newを使用します。

    dotnet new aspire-servicedefaults --output ServiceDefaults
    
  2. ASP.NET アプリケーションから ServiceDefaults プロジェクトを参照します。 Visual Studio で [追加]>[プロジェクト参照] を選択し、ServiceDefaults プロジェクトを選択します。

  3. アプリケーション ビルダーの初期化の一環として、OpenTelemetry セットアップ関数 ConfigureOpenTelemetry() を呼び出します。

    var builder = WebApplication.CreateBuilder(args)
    builder.ConfigureOpenTelemetry(); // Extension method from ServiceDefaults.
    var app = builder.Build();
    app.MapGet("/", () => "Hello World!");
    app.Run();
    

完全なチュートリアルについては、「例: OTLP で OpenTelemetry を使用する」とスタンドアロンのアスパイア ダッシュボードを参照してください。

試験的な接続トレース

HttpClient の問題やボトルネックのトラブルシューティングを行うときは、HTTP 要求の送信時に時間が費やされている場所を確認することが重要な場合があります。 多くの場合、問題は HTTP 接続の確立中に発生します。これは通常、DNS 参照、TCP 接続、TLS ハンドシェイクに分類されます。

.NET 9 では、接続確立の DNS、TCP、TLS の各フェーズを表す 3 つの子スパンを持つ HTTP connection setup スパンを追加する試験的な接続トレースが導入されました。 接続トレースの HTTP 部分は、SocketsHttpHandler内に実装されます。つまり、アクティビティ モデルは、基になる接続プールの動作を考慮する必要があります。

手記

SocketsHttpHandlerでは、接続と要求には独立したライフサイクルがあります。 プールされた接続 は、長時間存続し、多くの要求を処理できます。 要求を行うときに、接続プールですぐに使用可能な接続がない場合、要求は要求キューに追加され、使用可能な接続を待機します。 待機中の要求と接続の間に直接的な関係はありません。 別の接続が使用可能になったときに接続プロセスが開始された可能性があります。この場合、解放された接続が使用されます。 その結果、HTTP connection setup スパンは HTTP client request スパンの子としてモデル化されません。代わりに、スパン リンクが使用されます。

.NET 9 では、詳細な接続情報の収集を可能にするために、次のスパンが導入されました。

名前 ActivitySource 説明
HTTP wait_for_connection Experimental.System.Net.Http.Connections HTTP client request スパンの子スパン。要求が要求キュー内の利用可能な接続を待機する時間間隔を表します。
HTTP connection_setup Experimental.System.Net.Http.Connections HTTP 接続の確立を表します。 独自の TraceId を持つ個別のトレース ルート スパン。 HTTP client request スパンには、HTTP connection_setupへのリンクが含まれている場合があります。
DNS lookup Experimental.System.Net.NameResolution Dns クラスによって実行される DNS 参照。
socket connect Experimental.System.Net.Sockets Socket 接続の確立。
TLS handshake Experimental.System.Net.Security SslStreamによって実行される TLS クライアントまたはサーバー ハンドシェイク。

手記

対応する ActivitySource 名はプレフィックス Experimentalで始まります。これらのスパンは、運用環境でどれだけうまく機能するかについて学習するため、将来のバージョンで変更される可能性があるためです。

これらのスパンは、ワークロードが多い運用シナリオでは 24 時間 365 日使用するには冗長すぎるため、ノイズが多く、このレベルのインストルメンテーションは通常必要ありません。 ただし、接続の問題を診断しようとしている場合や、ネットワークと接続の待機時間がサービスに与える影響をより深く理解しようとしている場合は、他の方法では収集しにくい分析情報が提供されます。

Experimental.System.Net.Http.Connections ActivitySource が有効になっている場合、HTTP client request スパン には、要求を提供する接続に対応する HTTP connection_setup スパンへのリンクが含まれます。 HTTP 接続は有効期間が長い場合があり、その結果、各要求アクティビティからの接続スパンへのリンクが多数発生する可能性があります。 一部の APM 監視ツールは、スパン間のリンクを積極的にウォークしてビューを構築するため、このスパンを含めると、ツールが多数のリンクを考慮するように設計されていない場合に問題が発生する可能性があります。

次の図は、スパンの動作とその関係を示しています。

接続は長期間にわたります。

チュートリアル: .NET 9 での実験用接続トレースの使用

このチュートリアルでは、.NET 9 アスパイア スターター アプリ を使用して接続トレース方法を示しますが、他の監視ツール とも簡単に設定できます。 重要な手順は、ActivitySources を有効にすることです。

  1. dotnet newを使用して、.NET Aspire 9 Starter App を作成します。

    dotnet new aspire-starter-9 --output ConnectionTracingDemo
    

    または、Visual Studio で次の手順を実行します。

    Visual Studio

  2. ServiceDefaults プロジェクトで Extensions.cs を開き、トレース構成コールバックで接続用の ActivitySources を追加する ConfigureOpenTelemetry メソッドを編集します。

    .WithTracing(tracing =>
    {
        tracing.AddAspNetCoreInstrumentation()
            // Instead of using .AddHttpClientInstrumentation()
            // .NET 9 allows to add the ActivitySources directly.
            .AddSource("System.Net.Http")
            // Add the experimental connection tracking ActivitySources using a wildcard.
            .AddSource("Experimental.System.Net.*");
    });
    
  3. ソリューションを開始します。 これにより、.NET アスパイア ダッシュボードが開きます。

  4. webfrontend アプリの [天気] ページに移動して、apiserviceに対する HttpClient 要求を生成します。

  5. ダッシュボードに戻り、トレース ページに移動します。 webfrontend: GET /weather トレースを開きます。

    アスパイア ダッシュボード

接続インストルメンテーションを有効にして HTTP 要求が行われると、クライアント要求スパンに対して次の変更が表示されます。

  • 接続を確立する必要がある場合、またはアプリが接続プールからの接続を待機している場合は、接続を待機する遅延を表す追加の HTTP wait_for_connection スパンが表示されます。 これは、コードで行われている HttpClient 要求と、要求の処理が実際に開始されるタイミングの間の遅延を理解するのに役立ちます。 前の図では、次のようになります。
    • 選択したスパンは HttpClient 要求です。
    • 次のスパンは、要求が接続の確立を待機するために費やした時間を表します。
    • 黄色の最後のスパンは、要求を処理する宛先からのスパンです。
  • HttpClient スパンには、要求で使用される HTTP 接続を作成するアクティビティを表す HTTP connection_setup スパンへのリンクがあります。

接続設定スパンはアスパイア ダッシュボード にあります。

前述のように、HTTP connection_setup スパンは、その有効期間が個々のクライアント要求から独立しているため、独自の TraceId を持つ個別のスパンです。 このスパンには、通常、子スパン DNS lookup、(TCP) socket connect、および TLS client handshakeがあります。

濃縮

場合によっては、既存の System.Net トレース機能を拡張する必要があります。 通常、これは組み込みアクティビティに追加のタグ/属性を挿入することを意味します。 これをエンリッチメントと呼びます。

OpenTelemetry インストルメンテーション ライブラリのエンリッチメント API

HTTP クライアント要求アクティビティにタグ/属性を追加する最も簡単な方法は、OpenTelemetry HttpClient および HttpWebRequest インストルメンテーション ライブラリの HttpClient エンリッチメント API を使用することです。 これには、OpenTelemetry.Instrumentation.Http パッケージへの依存関係を取得する必要があります。

手動エンリッチメント

HTTP client request アクティビティのエンリッチメントを手動で実装できます。 そのためには、アクティビティが完了する前に、要求アクティビティのスコープで実行されているコード内の Activity.Current にアクセスする必要があります。 これを行うには、IObserver<DiagnosticListener> を実装し、それを AllListeners にサブスクライブして、ネットワーク アクティビティが発生している場合のコールバックを取得します。 実際、OpenTelemetry HttpClient および HttpWebRequest インストルメンテーション ライブラリはこのように実装されています。 コード例については、DiagnosticSourceSubscriber.cs のサブスクリプション コードと、通知が委任される HttpHandlerDiagnosticListener.cs の基になる実装を参照してください。

さらにトレースが必要な場合

トレースを介して公開できるその他の有用な情報に関する提案がある場合は、dotnet/runtime の問題を作成します。