次の方法で共有


OpenTelemetry を使用した .NET の監視

アプリケーションを実行するときは、アプリのパフォーマンスを把握し、潜在的な問題を大きくなる前に検出する必要があります。 これを行うには、アプリからログやメトリックなどのテレメトリ データを出力し、そのデータを監視して分析します。

可観測性とは

分散システムのコンテキストでの監視とは、各コンポーネントの状態に関するテレメトリを監視および分析し、パフォーマンスの変化を監視し、それらの変化が発生した理由を診断する機能のことです。 侵入性があり、アプリケーションの動作に影響を与える可能性があるデバッグとは異なり、監視はプライマリ操作に対して透過的であり、パフォーマンスへの影響が継続的に使用できる程度に十分小さくなるように意図したものです。

監視は、一般的に次の組み合わせを使用して行われます。

  • ログは受信要求、特定のコンポーネントでの失敗、なされた注文などの個々の操作を記録します。
  • メトリックは完了した要求、アクティブな要求、販売されたウィジェットの数や要求の待機時間のヒストグラムなどのカウンターとゲージを測定します。
  • 分散トレースは、時間が費やされている場所を確認し特定の失敗を追跡できるように分散システム内のコンポーネント間の要求とアクティビティを追跡します。

ログ、メトリック、分散トレースは、合わせて "監視の 3 つの柱" と呼ばれています。

各柱には、次に示すものからのテレメトリ データが含まれている可能性があります。

  • ガベージ コレクターや JIT コンパイラなどの .NET ランタイム。
  • Kestrel (ASP.NET Web サーバー) や HttpClient などのライブラリ。
  • 自分のコードによって出力されるアプリケーション固有のテレメトリ。

.NET における監視方法

.NET アプリケーションで監視を実現するには、次のようないくつかの異なる方法があります。

  • OpenTelemetry などのライブラリを参照して使用する明示的なコード。 ソース コードにアクセスでき、アプリを再ビルドできる場合は、これが最も強力で構成しやすいメカニズムです。
  • EventPipe を使用したアウトプロセス。 dotnet-monitor などのツールは、ログとメトリックをリッスンした後に、どんなコードにも影響を与えずにそれらを処理できます。
  • スタートアップ フックを使用すると、アセンブリをプロセスに挿入でき、それによってインストルメンテーションを収集できます。 この方法の例が OpenTelemetry .NET 自動インストルメンテーションです。

OpenTelemetry とは何ですか?

OpenTelemetry (OTel) は、テレメトリ データの収集と出力のためのクロスプラットフォームのオープンソース標準です。 OpenTelemetry には次のものが含まれます。

  • コードの実行中にテレメトリ データを記録するために使用するライブラリの API
  • アプリ開発者が記録されたデータのどの部分をネットワーク経由で送信するか、それをどこに送信するか、およびそれをどのようにフィルター処理、バッファリング、エンリッチ、変換するかを構成するために使用できる API
  • セマンティック規則は、テレメトリ データの名前付けとコンテンツに関するガイダンスを提供します。 テレメトリ データを生成するアプリと、データを受け取るツールが、ツールが効果的な分析を提供できるように、さまざまな種類のデータの意味と役立つデータの種類について合意することが重要です。
  • エクスポーターのインターフェイス。 エクスポーターは、テレメトリ データを特定の形式でさまざまなテレメトリ バックエンドに送信できるようにするプラグインです。
  • OTLP ワイヤ プロトコルは、テレメトリ データ送信用のベンダーに依存しないネットワーク プロトコル オプションです。 一部のツールとベンダーは、既存の専用プロトコルに加えて、このプロトコルをサポートしています。

OTel を使用すると、PrometheusGrafana などのオープンソース システム、Azure Monitor (Microsoft の Azure における APM 製品)、あるいは OpenTelemetry と提携する多くの APM ベンダーの製品など、さまざまな APM システムを使用できます。

.NET を含むほとんどの言語とプラットフォームには、OpenTelemetry の実装があります。

OpenTelemetry の .NET 実装

.NET はフレームワーク内でログ、メトリック、アクティビティ API を提供するため、.NET の OpenTelemetry 実装は他のプラットフォームとは少し異なります。 これは OTel はライブラリ作成者が使用する API を提供する必要がないことを意味します。 .NET の OTel 実装は、インストルメンテーションのために次のプラットフォーム API を使用します。

.NET OTel アーキテクチャ

OTel の働きは、それらの API やその他のソースから (インストルメンテーション ライブラリを介して) テレメトリを収集し、保存と分析のためにアプリケーション パフォーマンス監視 (APM) システムにエクスポートすることです。 OTel が業界標準としてもたらす利点は、収集のための一般的なメカニズム、テレメトリ データのための一般的なスキーマとセマンティクス、および APM がどのように OTel と統合できるかを決める API です。 OTel を使用すると、アプリケーションは APM 固有の API やデータ構造を使用する必要がなく、OTel 標準に基づいて動作します。 APM は、APM 固有のエクスポーター コンポーネントを実装することも、APM システムにテレメトリ データをエクスポートするための新しいワイヤ標準である OTLP を使用することもできます。

OpenTelemetry パッケージ

.NET の OpenTelemetry は、次に示すいくつかのカテゴリを形成する一連の NuGet パッケージとして実装されています。

  • Core API
  • インストルメンテーション - これらのパッケージは、ランタイムおよび共通ライブラリからインストルメンテーションを収集します。
  • エクスポーター - これらは、Prometheus、Jaeger、OTLP などの APM システムとインターフェイス接続します。

次の表は、主要なパッケージを示します。

パッケージ名 説明
OpenTelemetry コア OTEL 機能を提供するメイン ライブラリ
OpenTelemetry.Instrumentation.AspNetCore ASP.NET Core と Kestrel のインストルメンテーション
OpenTelemetry.Instrumentation.GrpcNetClient 送信 gRPC 呼び出しを追跡するための gRPC クライアントのインストルメンテーション
OpenTelemetry.Instrumentation.Http 送信 HTTP 呼び出しを追跡するための HttpClient および HttpWebRequest のインストルメンテーション
OpenTelemetry.Instrumentation.SqlClient データベース操作をトレースするために使用される SqlClient のインストルメンテーション
OpenTelemetry.Exporter.Console コンソールのエクスポーターで、一般的にどのテレメトリがエクスポートされているかを診断するために使用されます
OpenTelemetry.Exporter.OpenTelemetryProtocol OTLP プロトコルを使用したエクスポーター
OpenTelemetry.Exporter.Prometheus.AspNetCore ASP.NET Core エンドポイントを使用して実装された Prometheus のエクスポーター
OpenTelemetry.Exporter.Zipkin Zipkin トレースのエクスポーター

例: Prometheus、Grafana、Jaeger を使用する

この例では、メトリック収集に Prometheus、ダッシュボード作成に Grafana、分散トレースを表示するためには Jaeger を使用します。

1.プロジェクトを作成する

Visual Studio の ASP.NET Core Empty テンプレートまたは次の .NET CLI コマンドを使用して、単純な Web API プロジェクトを作成します。

dotnet new web

2. メトリックおよびアクティビティ定義を追加する

次のコードは、API が呼び出された回数の新しいメトリック (greetings.count) と、新しいアクティビティ ソース (OtPrGrYa.Example) を定義します。

// Custom metrics for the application
var greeterMeter = new Meter("OtPrGrYa.Example", "1.0.0");
var countGreetings = greeterMeter.CreateCounter<int>("greetings.count", description: "Counts the number of greetings");

// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OtPrGrJa.Example");

3. API エンドポイントを作成する

app.MapGet("/", SendGreeting);
async Task<String> SendGreeting(ILogger<Program> logger)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");

    // Log a message
    logger.LogInformation("Sending greeting");

    // Increment the custom counter
    countGreetings.Add(1);

    // Add a tag to the Activity
    activity?.SetTag("greeting", "Hello World!");

    return "Hello World!";
}

注意

API 定義は、OpenTelemetry に固有のものは何も使用しません。 監視のために .NET API を使用します。

4. OpenTelemetry パッケージを参照する

NuGet パッケージ マネージャーまたはコマンド ラインを使用して、次の NuGet パッケージを追加します。

<ItemGroup>
   <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.5.0-rc.1" />
   <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
   <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.5.0-beta.1" />
</ItemGroup>

注意

OTel API は絶えず進化し続けるので、最新バージョンを使用してください。

5. OpenTelemetry と適切なプロバイダーを構成する

var tracingOtlpEndpoint = builder.Configuration["OTLP_ENDPOINT_URL"];
var otel = builder.Services.AddOpenTelemetry();

// Configure OpenTelemetry Resources with the application name
otel.ConfigureResource(resource => resource
    .AddService(serviceName: builder.Environment.ApplicationName));

// Add Metrics for ASP.NET Core and our custom metrics and export to Prometheus
otel.WithMetrics(metrics => metrics
    // Metrics provider from OpenTelemetry
    .AddAspNetCoreInstrumentation()
    .AddMeter(greeterMeter.Name)
    // Metrics provides by ASP.NET Core in .NET 8
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
    .AddPrometheusExporter());

// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
    if (tracingOtlpEndpoint != null)
    {
        tracing.AddOtlpExporter(otlpOptions =>
         {
             otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
         });
    }
    else
    {
        tracing.AddConsoleExporter();
    }
});

このコードは、ASP.NET Core インストルメンテーションを使用して、ASP.NET Core からメトリックとアクティビティを取得します。 また、メトリックとトレース用にそれぞれ Metrics プロバイダーと ActivitySource プロバイダーを登録します。

このコードはメトリックに Prometheus エクスポーターを使用し、これは ASP.NET Core を使用してエンドポイントをホストするため、次も追加する必要があります。

// Configure the Prometheus scraping endpoint
app.MapPrometheusScrapingEndpoint();

6. プロジェクトを実行する

プロジェクトを実行し、ブラウザーまたは curl を使用して API にアクセスします。

curl -k http://localhost:7275

ページが要求されるたびに、行われたグリーティングの数のためのカウントをインクリメントします。 同じベース URL でパス /metrics を使用して、メトリック エンドポイントにアクセスできます。

6.1 ログ出力

コードのログ ステートメントは、ILogger を使用して出力されます。 既定では、出力がコンソールに送信されるようにコンソール プロバイダーが有効になっています。

.NET からログを出力できる方法には、次のようないくつかのオプションがあります。

  • stdout および stderr 出力は、Kubernetes などのコンテナー システムによってログ ファイルにリダイレクトされます。
  • ILogger と統合されるログ ライブラリの使用。これには SerilogNLog が含まれます。
  • OTLP や以下でさらに詳しく述べる Azure Monitor エクスポーターなどの OTel のログ プロバイダーの使用。

6.2 メトリックにアクセスする

/metrics エンドポイントを使用してメトリックにアクセスできます。

curl -k https://localhost:7275/
Hello World!

curl -k https://localhost:7275/metrics
# TYPE greetings_count counter
# HELP greetings_count Counts the number of greetings
greetings_count 1 1686894204856

# TYPE current_connections gauge
# HELP current_connections Number of connections that are currently active on the server.
current_connections{endpoint="127.0.0.1:7275"} 1 1686894204856
current_connections{endpoint="[::1]:7275"} 0 1686894204856
current_connections{endpoint="[::1]:5212"} 1 1686894204856
...

メトリック出力は、エンドポイントが要求された時点でのメトリックのスナップショットです。 結果は Prometheus の開示形式で提供され、これは人間も判読できますが、Prometheus にとって理解しやすい形式となっています。 このトピックは、次のステージでカバーされます。

6.3 トレースにアクセスする

サーバーのコンソールを見ると、コンソール トレース エクスポーターからの出力が確認でき、これは人間が判読できる形式で情報を出力します。 これには、次のようなカスタム ActivitySource からのアクティビティと ASP.NET Core からのアクティビティという 2 つのアクティビティが表示されているはずです。

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             3b7a891f55b97f1a
Activity.TraceFlags:         Recorded
Activity.ParentSpanId:       645071fd0011faac
Activity.ActivitySourceName: OtPrGrYa.Example
Activity.DisplayName:        GreeterActivity
Activity.Kind:               Internal
Activity.StartTime:          2023-06-16T04:50:26.7675469Z
Activity.Duration:           00:00:00.0023974
Activity.Tags:
    greeting: Hello World!
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             645071fd0011faac
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName:        /
Activity.Kind:               Server
Activity.StartTime:          2023-06-16T04:50:26.7672615Z
Activity.Duration:           00:00:00.0121259
Activity.Tags:
    net.host.name: localhost
    net.host.port: 7275
    http.method: GET
    http.scheme: https
    http.target: /
    http.url: https://localhost:7275/
    http.flavor: 1.1
    http.user_agent: curl/8.0.1
    http.status_code: 200
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

1 つ目は、自分が作成した内部カスタム アクティビティです。 2 つ目は、要求に対して ASP.NET によって作成されたもので、HTTP 要求プロパティのタグが含まれています。 両方に同じ TraceId が含まれていることがわかります。これは 1 つのトランザクションを特定するもので、分散システムではトランザクションに含まれる各サービスからのトレースを関連付けるために使用できます。 ID は HTTP ヘッダーとして送信されます。 ASP.NET Core は、要求を受信したときに存在しない場合に TraceId を割り当てます。 HttpClient は、既定で送信要求にヘッダーを含めます。 各アクティビティには SpanId があり、これは各アクティビティを一意に識別する TraceIdSpanId の組み合わせです。 Greeter アクティビティに対しては、その HTTP アクティビティの SpanId にマッピングされる ParentSpanId を介してその HTTP アクティビティが親として設定されます。

後のステージでは、分散トレースを視覚化するために、このデータを Jaeger にフィードします。

7. Prometheus を使用してメトリックを収集する

Prometheus は、メトリック収集、集計、および時系列データベース システムです。 各サービスのメトリック エンドポイントを使用してこれを構成すると、値を定期的にスクレイピングして時系列データベースに保存します。 その後、必要に応じてそれらを分析して処理できます。

Prometheus 形式で公開されるメトリック データは、プロセスのメトリックの特定の時点のスナップショットです。 メトリック エンドポイントに要求が行われるたびに、現在の値を報告します。 現在の値は興味深いものの、傾向を確認し値が異常な場合の検出を行うために履歴値と比較した方がより価値が高くなります。 一般的に、サービスには、ブラック フライデーにおけるショッピングの急増など、時刻や世界のイベントに基づく使用量のスパイクがあります。 値を過去の傾向と比較することで、値が異常な場合や、メトリックが時間の経過と共にゆっくりと悪化している場合を検出できます。

このプロセスは、これらのメトリック スナップショットのどの履歴も保存しません。 その機能をプロセスに追加すると、リソースが大量に消費される可能性があります。 また、分散システムでは、通常、各ノードの複数のインスタンスがあるため、それらのすべてからメトリックを収集した後に集計を行い履歴値と比較できることが望まれます。

7.1 Prometheus のインストールと構成

https://prometheus.io/download/ から自分のプラットフォーム用の Prometheus をダウンロードし、ダウンロード内容を展開します。

実行中のサーバーの出力の先頭を確認して、http エンドポイントのポート番号を取得します。 次に例を示します。

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7275
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5212

Prometheus YAML 構成ファイルを変更して、HTTP スクレイピング エンドポイントのポートを指定し、スクレイピング間隔を低く設定します。 たとえば次のような点です。

  scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"
    - scrape_interval: 1s # poll very quickly for a more responsive demo

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    scrape_interval: 1s # poll very quickly for a more responsive demo
    static_configs:
      - targets: ["localhost:5212"]

Prometheus を起動し、次のように出力で実行されているポート (通常は 9090) を確認します。

>prometheus.exe
...
ts=2023-06-16T05:29:02.789Z caller=web.go:562 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090

ブラウザーでこの URL を開きます。 Prometheus UI で、メトリックのクエリを実行できるようになっているはずです。 次の図で強調表示されているボタンを使用して、メトリック エクスプローラーを開きます。ここには使用可能なすべてのメトリックが示されます。

Prometheus メトリック エクスプローラー

greetings_count メトリックを選択して、値のグラフを表示します。

greetings_count のグラフ

8. Grafana を使用してメトリック ダッシュボードを作成する

Grafana は、Prometheus またはその他のデータ ソースに基づいてダッシュボードとアラートを作成できるダッシュボード製品です。

自分のプラットフォーム用の手順に従って、https://grafana.com/oss/grafana/ から OSS バージョンの Grafana をダウンロードしてインストールします。 インストールが完了したら、Grafana は通常、ポート 3000 で実行されるため、ブラウザーで http://localhost:3000 を開きます。 ログインする必要があります。既定のユーザー名とパスワードはどちらも admin です。

ハンバーガー メニューから接続を選択し、テキスト prometheus を入力してエンドポイントの種類を選択します。 [Prometheus データ ソースの作成] を選択して、新しいデータ ソースを追加します。

Prometheus への Grafana の接続

次のプロパティを設定する必要があります。

  • Prometheus サーバー URL: http://localhost:9090/ (必要に応じてポートを変更)

[保存 & テスト] を選択して構成を検証します。

成功メッセージが表示されたら、ダッシュボードを構成できます。 成功メッセージのポップアップに表示される [ダッシュボードの構築] リンクをクリックします。

[視覚化の追加] を選択した後に、先ほどデータ ソースとして追加した Prometheus データ ソースを選択します。

ダッシュボード パネル デザイナーが表示されるはずです。 画面の下半分で、クエリを定義できます。

greetings_count を使用する Grafana クエリ

greetings_count メトリックを選択した後に、[クエリの実行] を選択して結果を表示します。

Grafana を使用すると、任意の数のメトリックを追跡する洗練されたダッシュボードを設計できます。

.NET の各メトリックは追加のディメンションを持つことができ、これらはデータのパーティション分割に使用できるキーと値のペアです。 ASP.NET メトリックはすべて、カウンターに適用できる多数のディメンションを特徴とします。 たとえば、Microsoft.AspNetCore.Hostingcurrent-requests カウンターには次のディメンションがあります。

属性 Type 説明 プレゼンス
method string HTTP 要求メソッド。 GET; POST; HEAD Always (常に)
scheme string 使用されるプロトコルを特定する URI スキーム。 http; https 常時
host string 要求を受信したローカル HTTP サーバーの名前。 localhost 常時
port int 要求を受信したローカル HTTP サーバーのポート。 8080 既定値 (http は 80、https は 443) でない場合に追加

Grafana のグラフは、通常、ディメンションの一意の組み合わせごとにパーティション分割されます。 ディメンションは、Grafana クエリでデータをフィルター処理または集計するために使用できます。 たとえば、current_requests をグラフ化すると、ディメンションの組み合わせごとにパーティション分割された値が表示されます。 ホストのみに基づいてフィルター処理するには、Sum の操作を追加し、ラベル値として host を使用します。

Grafana のホストごとの current_requests

9. Jaeger を使用した分散トレース

手順 6 では、分散トレース情報がコンソールへ公開されているのを確認しました。 この情報は、アクティビティの作業単位を追跡します。 一部のアクティビティは、ASP.NET による要求の処理を表すものなど、プラットフォームによって自動的に作成され、ライブラリとアプリ コードもアクティビティを作成できます。 グリーティングの例には、Greeter アクティビティがあります。 アクティビティは、TraceIdSpanId および ParentId タグを使用して関連付けられます。

分散システム内の各プロセスは、独自のアクティビティ情報のストリームを生成するので、メトリックと同様に、各トランザクションで行われた作業を視覚化できるようにアクティビティの収集、保存、関連付けを行うシステムが必要です。 Jaeger は、この収集と視覚化を可能にするオープンソース プロジェクトです。

ご使用のプラットフォーム用の Jaeger の最新のバイナリ配布アーカイブを https://www.jaegertracing.io/download/ からダウンロードします。

次に、簡単にアクセスできるローカルの場所にダウンロードを展開します。 次のように jaeger-all-in-one(.exe) 実行可能ファイルを実行します。

./jaeger-all-in-one --collector.otlp.enabled

コンソール出力を確認して、gRPC 経由で OTLP トラフィックをリッスンしているポートを見つけます。 たとえば次のような点です。

{"level":"info","ts":1686963686.3854616,"caller":"otlpreceiver@v0.78.2/otlp.go:83","msg":"Starting GRPC server","endpoint":"0.0.0.0:4317"}

この出力は、0.0.0.0:4317 でリッスンしていることを示します。そのため、そのポートを OTLP エクスポーターの宛先として構成できます。

プロジェクトの AppSettings.json ファイルを開き、次の行を追加して、必要がある場合はポートを変更します。

"OTLP_ENDPOINT_URL" :  "http://localhost:4317/"

グリーター プロセスがプロパティの変更を取得し、トレース情報の Jaeger への送信を開始できるように、グリーター プロセスを再起動します。

これで、Web ブラウザーから http://localhost:16686/ で Jaeger UI を表示できるはずです。

Jaeger のトレース取得用クエリ

トレースの一覧を表示するには、[サービス] ドロップダウンから OTel-Prometheus-grafana-Jaeger を選択します。 トレースを選択すると、そのトレースの一部としてアクティビティのガント チャートが表示されるはずです。 各操作をクリックすると、アクティビティの詳細が表示されます。

Jaeger 操作の詳細

分散システムでは、同じ Jaeger インストールがシステム全体のトランザクションを関連付けることができるように、すべてのプロセスからのトレースを同じ Jaeger インストールに送信することが望まれます。

アプリに自分自身に対する HTTP 呼び出しを行わせることで、アプリをもう少し面白くすることができます。

  • アプリケーションに HttpClient ファクトリを追加する

    builder.Services.AddHttpClient();
    
  • 入れ子になったグリーティング呼び出しを行うための新しいエンドポイントを追加する

    app.MapGet("/NestedGreeting", SendNestedGreeting);
    
  • アプリがトレース可能な HTTP 呼び出しを行えるようにエンドポイントを実装します。 この場合、アプリは人工的なループの中で自分自身を呼び戻します (実際にはデモ シナリオに対してのみ適用できます)。

    async Task SendNestedGreeting(int nestlevel, ILogger<Program> logger, HttpContext context, IHttpClientFactory clientFactory)
    {
        // Create a new Activity scoped to the method
        using var activity = greeterActivitySource.StartActivity("GreeterActivity");
    
        if (nestlevel <= 5)
        {
            // Log a message
            logger.LogInformation("Sending greeting, level {nestlevel}", nestlevel);
    
            // Increment the custom counter
            countGreetings.Add(1);
    
            // Add a tag to the Activity
            activity?.SetTag("nest-level", nestlevel);
    
            await context.Response.WriteAsync($"Nested Greeting, level: {nestlevel}\r\n");
    
            if (nestlevel > 0)
            {
                var request = context.Request;
                var url = new Uri($"{request.Scheme}://{request.Host}{request.Path}?nestlevel={nestlevel - 1}");
    
                // Makes an http call passing the activity information as http headers
                var nestedResult = await clientFactory.CreateClient().GetStringAsync(url);
                await context.Response.WriteAsync(nestedResult);
            }
        }
        else
        {
            // Log a message
            logger.LogError("Greeting nest level {nestlevel} too high", nestlevel);
            await context.Response.WriteAsync("Nest level too high, max is 5");
        }
    }
    

これにより、各レベルが前の呼び出しからの応答を待機するので、要求がピラミッドの形状を持つより興味深いグラフが作成されます。

Jaeger の入れ子になった依存関係の結果

例: Azure Monitor と Application Insights を使用する

前の例では、メトリックとトレースに個別のオープンソース アプリケーションを使用しました。 選択候補とできる多くの商用 APM システムがあります。 Azure では、主要なアプリケーション監視製品は Application Insights であり、これは Azure Monitor の一部です。

統合された APM 製品の利点の 1 つは、さまざまな監視データ ソースを関連付けることができる点です。 Azure Monitor を使用した ASP.NET エクスペリエンスをより簡単なものにするために、OpenTelemetry の構成という大変な仕事の大部分を行うラッパー パッケージが提供されています。

手順 5 のプロジェクトと同じものを使用して、NuGet 参照を次の 1 つのパッケージで置き換えます。

<ItemGroup>
  <PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.0.0-beta.4" />
</ItemGroup>

次に、OTel 初期化コードを次のように置き換えます。

var otel = builder.Services.AddOpenTelemetry();
otel.UseAzureMonitor();
otel.WithMetrics(metrics => metrics
    .AddMeter(greeterMeter.Name)
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel"));
otel.WithTracing(tracing =>
{
    tracing.AddSource(greeterActivitySource.Name);
});

UseAzureMonitor() は、Application Insights 用の一般的なインストルメンテーション ライブラリとエクスポーターを追加するマジックです。 カスタムの MeterActivitySource の名前を登録に追加するだけで済みます。

まだ Azure のお客様でない場合、https://azure.microsoft.com/free/ で無料アカウントを作成できます。 Azure Portal にログインし、既存の Application Insights リソースを選択するか、https://ms.portal.azure.com/#create/Microsoft.AppInsights を使用して新しいリソースを作成します。

Application Insights は、ポータル UI の右上にあるインストルメンテーション キーと接続文字列を使用してデータを保存および処理するためにどのインスタンスを使用するべきかを特定します。

Azure Portal の接続文字列

Azure App Service を使用している場合、この接続文字列は環境変数としてアプリケーションに自動的に渡されます。 他のサービスの場合、またはローカルで実行する場合は、APPLICATIONINSIGHTS_CONNECTION_STRING 環境変数を使用して、または appsettings.json 内で渡す必要があります。 ローカルで実行する場合は、次のように値を appsettings.json に追加するのが最も簡単です。

"AzureMonitor": {
    "ConnectionString": "InstrumentationKey=12345678-abcd-abcd-abcd-12345678..."
}

注意

値をインスタンスの値で置き換えます。

アプリケーションを実行すると、テレメトリが Application Insights に送信されます。 これで、アプリケーションのログ、メトリック、分散トレースを取得できるはずです。

ログ

App Insights のログ ビュー

Metrics

App Insights のメトリック ビュー

分散トレース

App Insights のトランザクション ビュー