.NET のネットワーク メトリック
メトリック は、時間の経過に伴って報告される数値測定値です。 通常は、アプリの正常性を監視し、アラートを生成するために使用されます。
.NET 8 以降では、System.Net.Http
コンポーネントと System.Net.NameResolution
コンポーネントがインストルメント化され、.NET の新しい System.Diagnostics.Metrics APIを使用してメトリクスを公開します。
これらのメトリックは、OpenTelemetry と協力して設計され、標準と一致していることを確認し、Prometheus や Grafanaなどの一般的なツールとうまく連携します。
また、多次元 。つまり、測定値はタグ (属性またはラベルとも呼ばれます) と呼ばれるキーと値のペアに関連付けられています。 タグを使用すると、分析に役立つ測定の分類が可能になります。
アドバイス
すべての組み込みインストルメントとその属性の包括的な一覧については、System.Net メトリックを参照してください。
System.Net メトリックを収集する
組み込みのメトリックインストルメンテーションを利用するには、これらのメトリックを収集するように .NET アプリを構成する必要があります。 これは通常、外部ストレージと分析のために、たとえば監視システムに変換することを意味します。
.NET でネットワーク メトリックを収集するには、いくつかの方法があります。
- 簡単で自己完結型の例を使用した簡単な概要については、「dotnet-counters を使用してメトリックを収集するを参照してください。
- production-time のメトリクスの収集と監視には、Grafana with OpenTelemetry and Prometheus または Azure Monitor Application Insights を使用できます。 ただし、これらのツールは複雑なため、開発時に使用するのが不便な場合があります。
- 開発時 メトリックの収集とトラブルシューティング、.NET Aspire を使用することをお勧めします。これは、アプリケーションでメトリックと分散トレースを開始し、問題をローカルで診断するためのシンプルで拡張可能な方法を提供します。
- また、ASP.NET プロジェクトに OpenTelemetry トレースとメトリック構成 API を導入する便利な方法である、アスパイア オーケストレーションなしで、サービスの既定値 プロジェクトを 再利用することもできます。
dotnet-counters を使用してメトリックを収集する
dotnet-counters
は、.NET メトリックのアドホック調査と第 1 レベルのパフォーマンス調査のためのクロスプラットフォーム コマンド ライン ツールです。
このチュートリアルでは、HTTP 要求をさまざまなエンドポイントに並列で送信するアプリを作成します。
dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics
Program.cs
の内容を次のサンプル コードに置き換えます。
using System.Net;
string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
using HttpClient client = new()
{
DefaultRequestVersion = HttpVersion.Version20
};
Console.WriteLine("Press any key to start.");
Console.ReadKey();
while (!Console.KeyAvailable)
{
await Parallel.ForAsync(0, Random.Shared.Next(20), async (_, ct) =>
{
string uri = uris[Random.Shared.Next(uris.Length)];
try
{
byte[] bytes = await client.GetByteArrayAsync(uri, ct);
await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
}
catch { await Console.Out.WriteLineAsync($"{uri} - failed."); }
});
}
dotnet-counters
がインストールされていることを確認します。
dotnet tool install --global dotnet-counters
HelloBuiltinMetrics アプリを起動します。
dotnet run -c Release
別の CLI ウィンドウで dotnet-counters
を開始し、監視するプロセス名とメーターを指定し、HelloBuiltinMetrics アプリでキーを押して要求の送信を開始します。 測定が着陸するとすぐに、dotnet-counters
はコンソールを最新の番号で継続的に更新します。
dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics
dotnet-counters 出力する
.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
を実行すると自動的に起動します。
クイック ウォークスルー
dotnet new
を使用して、.NET Aspire 9 Starter App を作成します。dotnet new aspire-starter-9 --output AspireDemo
または、Visual Studio で新しいプロジェクトを作成し、.NET Aspire 9 Starter App テンプレートを選択します。
Visual Studio
ServiceDefaults
プロジェクトでExtensions.cs
を開き、ConfigureOpenTelemetry
メソッドまでスクロールします。 ネットワーキング メーターをサブスクライブしているAddHttpClientInstrumentation()
の呼び出しに注目してください。.WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation(); })
.NET 8 以降では、
AddHttpClientInstrumentation()
を手動測定サブスクリプションに置き換えることができます。.WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddMeter("System.Net.Http") .AddMeter("System.Net.NameResolution") .AddRuntimeInstrumentation(); })
AppHost
プロジェクトを実行します。 これにより、アスパイア ダッシュボードが起動します。webfrontend
アプリの [天気] ページに移動して、apiservice
に対するHttpClient
要求を生成します。 ページを複数回更新して、複数の要求を送信します。ダッシュボードに戻り、メトリック ページに移動し、
webfrontend
リソースを選択します。 下にスクロールすると、組み込みのSystem.Net
メトリックを参照できるようになります。アスパイア ダッシュボード
.NET Aspire に関する詳細については、次をご覧ください。
.NET アスパイア オーケストレーションを使用せずにサービスの既定のプロジェクトを再利用する
アスパイア サービスの既定値プロジェクトは、オーケストレーションに AppHost などの .NET アスパイア の残りの部分を使用しない場合でも、ASP.NET プロジェクト用に OTel を構成する簡単な方法を提供します。 Service Defaults プロジェクトは、Visual Studio または dotnet new
を使用してプロジェクト テンプレートとして使用できます。 OTel を構成し、OTLP エクスポーターを設定します。 その後、OTel 環境変数 を使用して、テレメトリを送信するように OTLP エンドポイントを構成し、アプリケーションのリソース プロパティを指定できます。
.NET Aspire の外部 ServiceDefaults を使用する手順は次のとおりです。
Visual Studio で [新しいプロジェクトの追加] を使用して、ServiceDefaults プロジェクトをソリューションに追加するか、
dotnet new
を使用します。dotnet new aspire-servicedefaults --output ServiceDefaults
ASP.NET アプリケーションから ServiceDefaults プロジェクトを参照します。 Visual Studio で [追加]>[プロジェクト参照] を選択し、ServiceDefaults プロジェクトを選択します。
アプリケーション ビルダーの初期化の一環として、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 を使用する」とスタンドアロンのアスパイア ダッシュボードを参照してください。
OpenTelemetry と Prometheus を使用して Grafana でメトリックを表示する
Prometheus と Grafana を使用してサンプル アプリを接続する方法については、「Prometheus、Grafana、Jaegerでの OpenTelemetry の使用」のチュートリアルに従ってください。
さまざまなエンドポイントに並列要求を送信して HttpClient
を強調するには、次のエンドポイントを使用してサンプル アプリを拡張します。
app.MapGet("/ClientStress", async Task<string> (ILogger<Program> logger, HttpClient client) =>
{
string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
await Parallel.ForAsync(0, 50, async (_, ct) =>
{
string uri = uris[Random.Shared.Next(uris.Length)];
try
{
await client.GetAsync(uri, ct);
logger.LogInformation($"{uri} - done.");
}
catch { logger.LogInformation($"{uri} - failed."); }
});
return "Sent 50 requests to example.com and httpbin.org.";
});
上部のツールバーで + アイコンを選択し、その後に ダッシュボードを選択して、Grafana ダッシュボードを作成します。 表示されるダッシュボード エディターで、[タイトル] ボックスに「open HTTP/1.1 Connections」と入力し、[PromQL 式] フィールドに次のクエリを入力します。
sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})
[適用] を選択して [] を保存して新しいダッシュボードを表示します。 プール内のアクティブな HTTP/1.1 接続とアイドル状態の HTTP/1.1 接続の数が表示されます。
Grafana
濃縮
エンリッチメント は、カスタム タグ (属性またはラベルとも呼ばれます) をメトリックに追加することです。 これは、アプリがメトリックを使用して構築されたダッシュボードまたはアラートにカスタム分類を追加する場合に便利です。
http.client.request.duration
インストゥルメントは、HttpMetricsEnrichmentContextにコールバックを登録することでエンリッチメントをサポートします。
これは低レベルの API であり、HttpRequestMessage
ごとに個別のコールバック登録が必要であることに注意してください。
コールバック登録を 1 か所で行う簡単な方法は、カスタム DelegatingHandlerを実装することです。 これにより、内部ハンドラーに転送されてサーバーに送信される前に、要求をインターセプトして変更できます。
using System.Net.Http.Metrics;
using HttpClient client = new(new EnrichmentHandler() { InnerHandler = new HttpClientHandler() });
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");
sealed class EnrichmentHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpMetricsEnrichmentContext.AddCallback(request, static context =>
{
if (context.Response is not null) // Response is null when an exception occurs.
{
// Use any information available on the request or the response to emit custom tags.
string? value = context.Response.Headers.GetValues("Enrichment-Value").FirstOrDefault();
if (value != null)
{
context.AddCustomTag("enrichment_value", value);
}
}
});
return base.SendAsync(request, cancellationToken);
}
}
IHttpClientFactory
を使用している場合は、AddHttpMessageHandler を使用して EnrichmentHandler
を登録できます。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Net.Http.Metrics;
ServiceCollection services = new();
services.AddHttpClient(Options.DefaultName).AddHttpMessageHandler(() => new EnrichmentHandler());
ServiceProvider serviceProvider = services.BuildServiceProvider();
HttpClient client = serviceProvider.GetRequiredService<HttpClient>();
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=A");
await client.GetStringAsync("https://httpbin.org/response-headers?Enrichment-Value=B");
手記
パフォーマンス上の理由から、エンリッチメント コールバックは、http.client.request.duration
インストルメントが有効になっている場合にのみ呼び出されます。つまり、何かがメトリックを収集する必要があります。
dotnet-monitor
、Prometheus エクスポーター、MeterListener
、または MetricCollector<T>
を指定できます。
IMeterFactory
と IHttpClientFactory
の統合
HTTP メトリックは、分離性とテスト可能性を念頭に置いて設計されました。 これらの側面は、IMeterFactoryの使用によってサポートされます。これにより、メートルを互いに分離するために、カスタム Meter インスタンスによるメトリックの発行が可能になります。
既定では、グローバル Meter を使用してすべてのメトリックが出力されます。 Meter は System.Net.Http
ライブラリの内部です。 この動作は、カスタム IMeterFactory インスタンスを SocketsHttpHandler.MeterFactory または HttpClientHandler.MeterFactoryに割り当てることでオーバーライドできます。
手記
Meter.Name は、HttpClientHandler
および SocketsHttpHandler
によって出力されるすべてのメトリックに対する System.Net.Http
です。
.NET 8 以降で Microsoft.Extensions.Http
と IHttpClientFactory
を使用する場合、既定の IHttpClientFactory
実装では、IServiceCollection に登録されている IMeterFactory
インスタンスが自動的に選択され、内部で作成されるプライマリ ハンドラーに割り当てられます。
手記
.NET 8 以降、AddHttpClient メソッドは自動的に AddMetrics を呼び出してメトリック サービスを初期化し、既定の IMeterFactory 実装を IServiceCollectionに登録します。 既定の IMeterFactory では、インスタンス Meter が名前によってキャッシュされます。つまり、IServiceCollectionごとに、名前 System.Net.Http
の Meter が1つあります。
メトリックをテストする
次の例では、Microsoft.Extensions.Diagnostics.Testing
NuGet パッケージから xUnit、IHttpClientFactory
、MetricCollector<T>
を使用して単体テストの組み込みメトリックを検証する方法を示します。
[Fact]
public async Task RequestDurationTest()
{
// Arrange
ServiceCollection services = new();
services.AddHttpClient();
ServiceProvider serviceProvider = services.BuildServiceProvider();
var meterFactory = serviceProvider.GetService<IMeterFactory>();
var collector = new MetricCollector<double>(meterFactory,
"System.Net.Http", "http.client.request.duration");
var client = serviceProvider.GetRequiredService<HttpClient>();
// Act
await client.GetStringAsync("http://example.com");
// Assert
await collector.WaitForMeasurementsAsync(minCount: 1).WaitAsync(TimeSpan.FromSeconds(5));
Assert.Collection(collector.GetMeasurementSnapshot(),
measurement =>
{
Assert.Equal("http", measurement.Tags["url.scheme"]);
Assert.Equal("GET", measurement.Tags["http.request.method"]);
});
}
メトリックと EventCounters の違い
メトリックはその多次元性により、特にEventCounters よりも 機能が豊富です。 この多次元性により、Prometheus などのツールで高度なクエリを作成し、EventCounters では不可能なレベルで分析情報を取得できます。
ただし、.NET 8 の時点では、メトリックを使用してインストルメント化されるのは System.Net.Http
コンポーネントと System.Net.NameResolutions
コンポーネントだけです。つまり、System.Net.Sockets
や System.Net.Security
などの下位レベルのスタックのカウンターが必要な場合は、EventCounters を使用する必要があります。
さらに、メトリックと一致する EventCounters にはセマンティックの違いがいくつかあります。
たとえば、HttpCompletionOption.ResponseContentRead
を使用する場合、current-requests
EventCounter は、要求本文の最後のバイトが読み取られる時点まで、要求がアクティブであると見なします。
対応するメトリック http.client.active_requests
には、アクティブな要求をカウントするときに応答本文の読み取りに費やされた時間は含まれません。
さらにメトリックが必要ですか?
メトリックを介して公開できるその他の有用な情報に関する提案がある場合は、dotnet/runtime の問題作成します。
.NET