Metrik jaringan di .NET
Metrik adalah pengukuran numerik yang dilaporkan dari waktu ke waktu. Mereka biasanya digunakan untuk memantau kesehatan aplikasi dan menghasilkan pemberitahuan.
Dimulai dengan .NET 8, System.Net.Http
dan System.Net.NameResolution
komponen diinstrumentasikan untuk menerbitkan metrik menggunakan . API System.Diagnostics.Metrics baru NET.
Metrik ini dirancang bekerja sama dengan OpenTelemetry untuk memastikan metrik tersebut konsisten dengan standar dan bekerja dengan baik dengan alat populer seperti Prometheus dan Grafana.
Mereka juga multi-dimensi, yang berarti bahwa pengukuran dikaitkan dengan pasangan kunci-nilai yang disebut tag (alias atribut atau label) yang memungkinkan data dikategorikan untuk analisis.
Tip
Untuk daftar komprehensif semua instrumen bawaan bersama dengan atributnya, lihat metrik System.Net.
Mengumpulkan metrik System.Net
Ada dua bagian untuk menggunakan metrik dalam aplikasi .NET:
- Instrumentasi: Kode dalam pustaka .NET mengambil pengukuran dan mengaitkan pengukuran ini dengan nama metrik. .NET dan ASP.NET Core mencakup banyak metrik bawaan.
- Koleksi: Aplikasi .NET mengonfigurasi metrik bernama untuk dikirimkan dari aplikasi untuk penyimpanan dan analisis eksternal. Beberapa alat mungkin melakukan konfigurasi di luar aplikasi menggunakan file konfigurasi atau alat UI.
Bagian ini menunjukkan berbagai metode untuk mengumpulkan dan melihat metrik System.Net.
Contoh aplikasi
Demi tutorial ini, buat aplikasi sederhana yang mengirim permintaan HTTP ke berbagai titik akhir secara paralel.
dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics
Ganti konten Program.cs
dengan kode sampel berikut:
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)];
byte[] bytes = await client.GetByteArrayAsync(uri, ct);
await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
});
}
Melihat metrik dengan penghitung dotnet
dotnet-counters
adalah alat pemantauan performa lintas platform untuk pemantauan kesehatan ad-hoc dan investigasi performa tingkat pertama.
dotnet tool install --global dotnet-counters
Saat berjalan terhadap proses .NET 8+, dotnet-counters
memungkinkan instrumen yang ditentukan oleh --counters
argumen dan menampilkan pengukuran. Konsol ini terus menyegarkan konsol dengan angka terbaru:
dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics
Melihat metrik di Grafana dengan OpenTelemetry dan Prometheus
Gambaran Umum
- Adalah proyek sumber terbuka yang netral vendor yang didukung oleh Cloud Native Computing Foundation.
- Menstandarkan pembuatan dan pengumpulan telemetri untuk perangkat lunak cloud-native.
- Bekerja dengan .NET menggunakan API metrik .NET.
- Didukung oleh Azure Monitor dan banyak vendor APM.
Tutorial ini menunjukkan salah satu integrasi yang tersedia untuk metrik OpenTelemetry menggunakan proyek OSS Prometheus dan Grafana . Aliran data metrik terdiri dari langkah-langkah berikut:
API metrik .NET merekam pengukuran dari aplikasi contoh.
Pustaka OpenTelemetry yang berjalan di aplikasi menggabungkan pengukuran.
Pustaka pengekspor Prometheus membuat data agregat tersedia melalui titik akhir metrik HTTP. 'Pengekspor' adalah apa yang disebut OpenTelemetry pustaka yang mengirimkan telemetri ke backend khusus vendor.
Server Prometheus:
- Polling titik akhir metrik.
- Membaca data.
- Menyimpan data dalam database untuk persistensi jangka panjang. Prometheus mengacu pada membaca dan menyimpan data sebagai mengikis titik akhir.
- Dapat berjalan pada komputer yang berbeda.
Server Grafana:
- Mengkueri data yang disimpan di Prometheus dan menampilkannya di dasbor pemantauan berbasis web.
- Dapat berjalan pada komputer yang berbeda.
Mengonfigurasi contoh aplikasi untuk menggunakan pengekspor Prometheus OpenTelemetry
Tambahkan referensi ke pengekspor OpenTelemetry Prometheus ke aplikasi contoh:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Catatan
Tutorial ini menggunakan build pra-rilis dukungan Prometheus OpenTelemetry yang tersedia pada saat penulisan.
Perbarui Program.cs
dengan konfigurasi OpenTelemetry:
using OpenTelemetry.Metrics;
using OpenTelemetry;
using System.Net;
using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("System.Net.Http", "System.Net.NameResolution")
.AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "http://localhost:9184/" })
.Build();
string[] uris = ["http://example.com", "http://httpbin.org/get", "https://example.com", "https://httpbin.org/get"];
using HttpClient client = new()
{
DefaultRequestVersion = HttpVersion.Version20
};
while (!Console.KeyAvailable)
{
await Parallel.ForAsync(0, Random.Shared.Next(20), async (_, ct) =>
{
string uri = uris[Random.Shared.Next(uris.Length)];
byte[] bytes = await client.GetByteArrayAsync(uri, ct);
await Console.Out.WriteLineAsync($"{uri} - received {bytes.Length} bytes.");
});
}
Dalam kode sebelumnya:
AddMeter("System.Net.Http", "System.Net.NameResolution")
mengonfigurasi OpenTelemetry untuk mengirimkan semua metrik yang dikumpulkan oleh bawaanSystem.Net.Http
danSystem.Net.NameResolution
meter.AddPrometheusHttpListener
mengonfigurasi OpenTelemetry untuk mengekspos titik akhir HTTP metrik Prometheus pada port9184
.
Catatan
Konfigurasi ini berbeda untuk aplikasi ASP.NET Core, di mana metrik diekspor dengan OpenTelemetry.Exporter.Prometheus.AspNetCore
alih-alih HttpListener
. Lihat contoh ASP.NET Core terkait.
Jalankan aplikasi dan biarkan berjalan sehingga pengukuran dapat dikumpulkan:
dotnet run
Menyiapkan dan mengonfigurasi Prometheus
Ikuti langkah-langkah pertama Prometheus untuk menyiapkan server Prometheus dan mengonfirmasi bahwa prometheus berfungsi.
Ubah file konfigurasi prometheus.yml sehingga Prometheus mengekstrak titik akhir metrik yang diekspos aplikasi contoh. Tambahkan teks yang disorot berikut ini di bagian scrape_configs
:
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]
- job_name: 'OpenTelemetryTest'
scrape_interval: 1s # poll very quickly for a more responsive demo
static_configs:
- targets: ['localhost:9184']
Mulai prometheus
Muat ulang konfigurasi atau mulai ulang server Prometheus.
Konfirmasikan bahwa OpenTelemetryTest berada dalam status UP di halaman Target Status>portal web Prometheus.
Pada halaman Grafik portal web Prometheus, masukkan
http
dalam kotak teks ekspresi dan pilihhttp_client_active_requests
. Di tab grafik, Prometheus menunjukkan nilaihttp.client.active_requests
penghitung yang dipancarkan oleh aplikasi contoh.
Menampilkan metrik di dasbor Grafana
Ikuti instruksi standar untuk menginstal Grafana dan menyambungkannya ke sumber data Prometheus.
Buat dasbor Grafana dengan memilih + ikon di toolbar atas lalu pilih Dasbor. Di editor dasbor yang muncul, masukkan Buka Koneksi ion HTTP/1.1 di kotak Judul dan kueri berikut di bidang ekspresi PromQL:
sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})
- Pilih Terapkan untuk menyimpan dan menampilkan dasbor baru. Ini menampilkan jumlah koneksi HTTP/1.1 aktif vs diam di kumpulan.
Pengayaan
Pengayaan adalah penambahan tag kustom (alias atribut atau label) ke metrik. Ini berguna jika aplikasi ingin menambahkan kategorisasi kustom ke dasbor atau pemberitahuan yang dibangun dengan metrik.
Instrumen http.client.request.duration
ini mendukung pengayaan dengan mendaftarkan panggilan balik dengan HttpMetricsEnrichmentContext.
Perhatikan bahwa ini adalah API tingkat rendah dan pendaftaran panggilan balik terpisah diperlukan untuk setiap HttpRequestMessage
.
Cara sederhana untuk melakukan pendaftaran panggilan balik di satu tempat adalah dengan menerapkan kustom DelegatingHandler. Ini akan memungkinkan Anda untuk mencegat dan memodifikasi permintaan sebelum diteruskan ke handler dalam dan dikirim ke server:
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);
}
}
Jika Anda bekerja dengan IHttpClientFactory
, Anda dapat menggunakan AddHttpMessageHandler untuk mendaftarkan 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");
Catatan
Untuk alasan performa, panggilan balik pengayaan hanya dipanggil ketika http.client.request.duration
instrumen diaktifkan, yang berarti bahwa sesuatu harus mengumpulkan metrik.
Ini bisa menjadi dotnet-monitor
, pengekspor Prometheus, MeterListener
, atau MetricCollector<T>
.
IMeterFactory
dan IHttpClientFactory
integrasi
Metrik HTTP dirancang dengan pertimbangkan isolasi dan kemampuan pengujian. Aspek-aspek ini didukung oleh penggunaan IMeterFactory, yang memungkinkan penerbitan metrik oleh instans kustom Meter untuk menjaga Meter terisolasi satu sama lain.
Secara default, semua metrik dipancarkan oleh internal global Meter ke System.Net.Http
pustaka. Perilaku ini dapat ditimpa dengan menetapkan instans kustom IMeterFactory ke SocketsHttpHandler.MeterFactory atau HttpClientHandler.MeterFactory.
Catatan
Meter.Name adalah System.Net.Http
untuk semua metrik yang dipancarkan oleh HttpClientHandler
dan SocketsHttpHandler
.
Saat bekerja dengan Microsoft.Extensions.Http
dan IHttpClientFactory
di .NET 8+, implementasi default IHttpClientFactory
secara otomatis memilih instans IMeterFactory
yang terdaftar di IServiceCollection dan menetapkannya ke handler utama yang dibuatnya secara internal.
Catatan
Dimulai dengan .NET 8, AddHttpClient metode secara otomatis memanggil AddMetrics untuk menginisialisasi layanan metrik dan mendaftarkan implementasi default IMeterFactory dengan IServiceCollection. Instans Meter cache default IMeterFactory berdasarkan nama, yang berarti bahwa akan ada satu Meter dengan nama System.Net.Http
per IServiceCollection.
Menguji metrik
Contoh berikut menunjukkan cara memvalidasi metrik bawaan dalam pengujian unit menggunakan xUnit, IHttpClientFactory
, dan MetricCollector<T>
dari Microsoft.Extensions.Diagnostics.Testing
paket NuGet:
[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"]);
});
}
Metrik vs. EventCounters
Metrik lebih kaya fitur daripada EventCounters, terutama karena sifat multi-dimensinya. Multidimensi ini memungkinkan Anda membuat kueri canggih dalam alat seperti Prometheus dan mendapatkan wawasan tentang tingkat yang tidak dimungkinkan dengan EventCounters.
Namun demikian, pada .NET 8, hanya System.Net.Http
komponen dan System.Net.NameResolutions
yang diinstrumentasikan menggunakan Metrik, yang berarti bahwa jika Anda memerlukan penghitung dari tingkat tumpukan yang lebih rendah seperti System.Net.Sockets
atau System.Net.Security
, Anda harus menggunakan EventCounters.
Selain itu, ada beberapa perbedaan semantik antara Metrik dan EventCounters yang cocok.
Misalnya, saat menggunakan HttpCompletionOption.ResponseContentRead
, current-requests
EventCounter menganggap permintaan aktif hingga saat byte terakhir dari isi permintaan telah dibaca.
Rekan http.client.active_requests
metriknya tidak termasuk waktu yang dihabiskan untuk membaca isi respons saat menghitung permintaan aktif.
Perlu lebih banyak metrik?
Jika Anda memiliki saran untuk informasi berguna lainnya yang dapat diekspos melalui metrik, buat masalah dotnet/runtime.