Metrische netwerkgegevens in .NET
Metrische gegevens zijn numerieke metingen die in de loop van de tijd worden gerapporteerd. Ze worden meestal gebruikt om de status van een app te bewaken en waarschuwingen te genereren.
Vanaf .NET 8 worden de System.Net.Http
en de System.Net.NameResolution
onderdelen geïnstrueerd om metrische gegevens te publiceren met behulp van . De nieuwe SYSTEM.Diagnostics.Metrics-API van NET.
Deze metrische gegevens zijn ontworpen in samenwerking met OpenTelemetry om ervoor te zorgen dat ze consistent zijn met de standaard en goed werken met populaire hulpprogramma's zoals Prometheus en Grafana.
Ze zijn ook multidimensionaal, wat betekent dat metingen zijn gekoppeld aan sleutel-waardeparen die tags (a.k.a. kenmerken of labels) worden genoemd waarmee gegevens kunnen worden gecategoriseerd voor analyse.
Tip
Zie System.Net metrische gegevens voor een uitgebreide lijst met alle ingebouwde instrumenten samen met hun kenmerken.
Metrische gegevens voor System.Net verzamelen
Er zijn twee onderdelen voor het gebruik van metrische gegevens in een .NET-app:
- Instrumentatie: Code in .NET-bibliotheken neemt metingen en koppelt deze metingen aan een metrische naam. .NET en ASP.NET Core bevatten veel ingebouwde metrische gegevens.
- Verzameling: Een .NET-app configureert benoemde metrische gegevens die moeten worden verzonden vanuit de app voor externe opslag en analyse. Sommige hulpprogramma's kunnen configuraties uitvoeren buiten de app met behulp van configuratiebestanden of een ui-hulpprogramma.
In deze sectie ziet u verschillende methoden voor het verzamelen en weergeven van System.Net metrische gegevens.
Voorbeeld-app
Maak voor deze zelfstudie een eenvoudige app waarmee HTTP-aanvragen parallel naar verschillende eindpunten worden verzonden.
dotnet new console -o HelloBuiltinMetrics
cd ..\HelloBuiltinMetrics
Vervang de inhoud door Program.cs
de volgende voorbeeldcode:
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.");
});
}
Metrische gegevens weergeven met dotnet-tellers
dotnet-counters
is een platformoverschrijdend hulpprogramma voor prestatiebewaking voor ad-hocstatusbewaking en prestatieonderzoek op het eerste niveau.
dotnet tool install --global dotnet-counters
Bij uitvoering op basis van een .NET 8+-proces worden dotnet-counters
de instrumenten ingeschakeld die door het --counters
argument zijn gedefinieerd en worden de metingen weergegeven. De console wordt continu vernieuwd met de nieuwste nummers:
dotnet-counters monitor --counters System.Net.Http,System.Net.NameResolution -n HelloBuiltinMetrics
Metrische gegevens weergeven in Grafana met OpenTelemetry en Prometheus
Overzicht
- Is een leverancierneutraal opensource-project dat wordt ondersteund door de Cloud Native Computing Foundation.
- Standaardiseert het genereren en verzamelen van telemetrie voor cloudeigen software.
- Werkt met .NET met behulp van de metrische .NET-API's.
- Wordt goedgekeurd door Azure Monitor en veel APM-leveranciers.
In deze zelfstudie ziet u een van de integraties die beschikbaar zijn voor metrische gegevens van OpenTelemetry met behulp van de OSS Prometheus - en Grafana-projecten . De gegevensstroom met metrische gegevens bestaat uit de volgende stappen:
De metrische .NET-API's registreren metingen uit de voorbeeld-app.
De OpenTelemetry-bibliotheek die in de app wordt uitgevoerd, voegt de metingen samen.
De Prometheus-exportbibliotheek maakt de geaggregeerde gegevens beschikbaar via een eindpunt voor metrische HTTP-gegevens. 'Exporteur' is wat OpenTelemetry de bibliotheken aanroept die telemetrie verzenden naar leverancierspecifieke back-ends.
Een Prometheus-server:
- Peilt het eindpunt voor metrische gegevens.
- Leest de gegevens.
- Slaat de gegevens op in een database voor persistentie op lange termijn. Prometheus verwijst naar het lezen en opslaan van gegevens als het scrapen van een eindpunt.
- Kan worden uitgevoerd op een andere computer.
De Grafana-server:
- Query's uitvoeren op de gegevens die zijn opgeslagen in Prometheus en deze weergeven op een bewakingsdashboard op internet.
- Kan worden uitgevoerd op een andere computer.
De voorbeeld-app configureren voor het gebruik van de Prometheus-exporteur van OpenTelemetry
Voeg een verwijzing naar de OpenTelemetry Prometheus-exporteur toe aan de voorbeeld-app:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Notitie
In deze zelfstudie wordt gebruikgemaakt van een voorlopige build van de Prometheus-ondersteuning van OpenTelemetry die beschikbaar is op het moment van schrijven.
Bijwerken Program.cs
met OpenTelemetry-configuratie:
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.");
});
}
In de voorgaande code:
AddMeter("System.Net.Http", "System.Net.NameResolution")
configureert OpenTelemetry om alle metrische gegevens te verzenden die zijn verzameld door de ingebouwdeSystem.Net.Http
enSystem.Net.NameResolution
meters.AddPrometheusHttpListener
configureert OpenTelemetry om het HTTP-eindpunt voor metrische gegevens van Prometheus beschikbaar te maken op poort9184
.
Notitie
Deze configuratie verschilt voor ASP.NET Core-apps, waarbij metrische gegevens worden geëxporteerd OpenTelemetry.Exporter.Prometheus.AspNetCore
in plaats van HttpListener
. Zie het gerelateerde ASP.NET Core-voorbeeld.
Voer de app uit en laat deze actief zodat metingen kunnen worden verzameld:
dotnet run
Prometheus instellen en configureren
Volg de eerste stappen van Prometheus om een Prometheus-server in te stellen en te bevestigen dat deze werkt.
Wijzig het prometheus.yml configuratiebestand zodat Prometheus het eindpunt voor metrische gegevens verwijdert dat de voorbeeld-app weergeeft. Voeg de volgende gemarkeerde tekst toe in de scrape_configs
sectie:
# 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']
Prometheus starten
Laad de configuratie opnieuw of start de Prometheus-server opnieuw op.
Controleer of OpenTelemetryTest de UP-status heeft op de pagina Statusdoelen> van de Prometheus-webportal.
Voer
http
op de graph-pagina van de Prometheus-webportal het tekstvak voor expressies in en selecteerhttp_client_active_requests
. Op het grafiektabblad toont Prometheus de waarde van dehttp.client.active_requests
teller die wordt verzonden door de voorbeeld-app.
Metrische gegevens weergeven op een Grafana-dashboard
Volg de standaardinstructies om Grafana te installeren en deze te verbinden met een Prometheus-gegevensbron.
Maak een Grafana-dashboard door het + pictogram op de bovenste werkbalk te selecteren en vervolgens Dashboard te selecteren. Voer in de dashboardeditor die wordt weergegeven Http/1.1 open Verbinding maken ions in het vak Titel en de volgende query in het veld PromQL-expressie in:
sum by(http_connection_state) (http_client_open_connections{network_protocol_version="1.1"})
- Selecteer Toepassen om het nieuwe dashboard op te slaan en weer te geven. Hiermee wordt het aantal actieve en niet-actieve HTTP/1.1-verbindingen in de pool weergegeven.
Enrichment
Verrijking is de toevoeging van aangepaste tags (a.k.a. kenmerken of labels) aan een metrische waarde. Dit is handig als een app een aangepaste categorisatie wil toevoegen aan dashboards of waarschuwingen die zijn gebouwd met metrische gegevens.
Het http.client.request.duration
instrument ondersteunt verrijking door callbacks te registreren bij de HttpMetricsEnrichmentContext.
Houd er rekening mee dat dit een API op laag niveau is en dat er voor elke HttpRequestMessage
api een afzonderlijke callback-registratie nodig is.
Een eenvoudige manier om de callback-registratie op één plaats uit te voeren, is door een aangepaste DelegatingHandlerimplementatie uit te voeren. Hiermee kunt u de aanvragen onderscheppen en wijzigen voordat ze worden doorgestuurd naar de binnenhandler en naar de server worden verzonden:
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);
}
}
Als u werkt, IHttpClientFactory
kunt u het volgende gebruiken AddHttpMessageHandler om het EnrichmentHandler
volgende te registreren:
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");
Notitie
Om prestatieredenen wordt de callback voor verrijking alleen aangeroepen wanneer het http.client.request.duration
instrument is ingeschakeld, wat betekent dat er iets moet zijn om de metrische gegevens te verzamelen.
Dit kan zijn dotnet-monitor
, Prometheus-exporteur, een MeterListener
of een MetricCollector<T>
.
IMeterFactory
en IHttpClientFactory
integratie
HTTP-metrische gegevens zijn ontworpen met isolatie en testbaarheid in gedachten. Deze aspecten worden ondersteund door het gebruik van IMeterFactory, waardoor metrische gegevens kunnen worden gepubliceerd door een aangepast exemplaar Meter om meters gescheiden van elkaar te houden.
Standaard worden alle metrische gegevens verzonden door een globaal Meter intern naar de System.Net.Http
bibliotheek. Dit gedrag kan worden overschreven door een aangepast exemplaar IMeterFactory toe te wijzen aan SocketsHttpHandler.MeterFactory of HttpClientHandler.MeterFactory.
Notitie
Dit Meter.Name geldt System.Net.Http
voor alle metrische gegevens die worden verzonden door HttpClientHandler
en SocketsHttpHandler
.
Wanneer u met Microsoft.Extensions.Http
en IHttpClientFactory
op .NET 8+ werkt, kiest de standaard IHttpClientFactory
implementatie automatisch het IMeterFactory
exemplaar dat in de IServiceCollection instantie is geregistreerd en wijst deze toe aan de primaire handler die intern wordt gemaakt.
Notitie
Vanaf .NET 8 wordt de AddHttpClient methode automatisch aangeroepen AddMetrics om de metrische services te initialiseren en de standaard IMeterFactory implementatie bij IServiceCollectionte registreren. De exemplaren van de standaardcaches IMeterFactoryMeter op naam, wat betekent dat er één Meter met de naam System.Net.Http
per IServiceCollection.
Metrische gegevens testen
In het volgende voorbeeld ziet u hoe u ingebouwde metrische gegevens in eenheidstests valideert met behulp van xUnit, IHttpClientFactory
en MetricCollector<T>
vanuit het Microsoft.Extensions.Diagnostics.Testing
NuGet-pakket:
[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"]);
});
}
Metrische gegevens versus EventCounters
Metrische gegevens zijn uitgebreider dan EventCounters, met name vanwege hun multidimensionale aard. Met deze multidimensionale functionaliteit kunt u geavanceerde query's maken in hulpprogramma's zoals Prometheus en inzichten verkrijgen op een niveau dat niet mogelijk is met EventCounters.
Vanaf .NET 8 worden echter alleen de System.Net.Http
onderdelen System.Net.NameResolutions
geïnstrueerd met behulp van metrische gegevens, wat betekent dat als u tellers van de lagere niveaus van de stack nodig hebt, zoals System.Net.Sockets
of System.Net.Security
, u EventCounters moet gebruiken.
Bovendien zijn er enkele semantische verschillen tussen metrische gegevens en hun overeenkomende EventCounters.
Wanneer de EventCounter bijvoorbeeld een HttpCompletionOption.ResponseContentRead
current-requests
aanvraag beschouwt om actief te zijn tot het moment waarop de laatste byte van de aanvraagbody is gelezen.
De tegenhanger http.client.active_requests
voor metrische gegevens bevat niet de tijd die is besteed aan het lezen van de hoofdtekst van het antwoord bij het tellen van de actieve aanvragen.
Meer metrische gegevens nodig?
Als u suggesties hebt voor andere nuttige informatie die kan worden weergegeven via metrische gegevens, maakt u een probleem met dotnet/runtime.