Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article s’applique à : ✔️ .NET 6.0 et versions ultérieures ✔️ .NET Framework 4.6.1 et versions ultérieures
Le code instrumenté peut enregistrer des mesures numériques, mais les mesures doivent généralement être agrégées, transmises et stockées pour créer des métriques utiles pour la surveillance. Le processus d’agrégation, de transmission et de stockage des données est appelé collecte. Ce tutoriel présente plusieurs exemples de collecte de métriques :
- Remplissage des métriques dans Grafana avec OpenTelemetry et Prometheus.
- Affichage des métriques en temps réel avec
dotnet-counters
- Création d’un outil de collection personnalisé à l’aide de l’API .NET MeterListener sous-jacente.
Pour plus d’informations sur l’instrumentation et les options de métrique personnalisées, consultez Comparer les API de métrique.
Conditions préalables
- Sdk .NET 6.0 ou version ultérieure
Créer un exemple d’application
Avant que les métriques puissent être collectées, les mesures doivent être produites. Ce didacticiel crée une application dotée d'une instrumentation de mesure de base. Le runtime .NET dispose également de différentes métriques intégrées. Pour plus d’informations sur la création de nouvelles métriques à l’aide de l’API System.Diagnostics.Metrics.Meter , consultez le didacticiel d’instrumentation.
dotnet new console -o metric-instr
cd metric-instr
dotnet add package System.Diagnostics.DiagnosticSource
Remplacez le contenu de Program.cs
par le code suivant :
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hats-sold");
static void Main(string[] args)
{
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
}
Le code précédent simule la vente de chapeaux à intervalles aléatoires et de temps aléatoires.
Afficher les métriques avec dotnet-counters
dotnet-counters est un outil en ligne de commande qui peut afficher les métriques actives pour les applications .NET Core à la demande. Elle ne nécessite pas d’installation, ce qui l’rend utile pour les enquêtes ad hoc ou pour vérifier que l’instrumentation des métriques fonctionne. Il fonctionne avec les API basées sur System.Diagnostics.Metrics et sur les EventCounters.
Si l’outil dotnet-counters n’est pas installé, exécutez la commande suivante :
dotnet tool update -g dotnet-counters
Pendant l’exécution de l’exemple d’application, lancez dotnet-counters. La commande suivante montre un exemple de surveillance de toutes les mesures du compteur dotnet-counters
par HatCo.HatStore
. Le nom du compteur respecte la casse. Notre exemple d’application était metric-instr.exe, remplacez-le par le nom de votre exemple d’application.
dotnet-counters monitor -n metric-instr HatCo.HatStore
La sortie similaire à ce qui suit s’affiche :
Press p to pause, r to resume, q to quit.
Status: Running
[HatCo.HatStore]
hats-sold (Count / 1 sec) 4
dotnet-counters
peut être exécuté avec un autre ensemble de métriques pour voir une partie de l’instrumentation intégrée à partir du runtime .NET :
dotnet-counters monitor -n metric-instr
La sortie similaire à ce qui suit s’affiche :
Press p to pause, r to resume, q to quit.
Status: Running
[System.Runtime]
% Time in GC since last GC (%) 0
Allocation Rate (B / 1 sec) 8,168
CPU Usage (%) 0
Exception Count (Count / 1 sec) 0
GC Heap Size (MB) 2
Gen 0 GC Count (Count / 1 sec) 0
Gen 0 Size (B) 2,216,256
Gen 1 GC Count (Count / 1 sec) 0
Gen 1 Size (B) 423,392
Gen 2 GC Count (Count / 1 sec) 0
Gen 2 Size (B) 203,248
LOH Size (B) 933,216
Monitor Lock Contention Count (Count / 1 sec) 0
Number of Active Timers 1
Number of Assemblies Loaded 39
ThreadPool Completed Work Item Count (Count / 1 sec) 0
ThreadPool Queue Length 0
ThreadPool Thread Count 3
Working Set (MB) 30
Pour plus d’informations, consultez dotnet-counters. Pour en savoir plus sur les métriques dans .NET, consultez les métriques intégrées.
Afficher les métriques dans Grafana avec OpenTelemetry et Prometheus
Aperçu
- Est un projet open source neutre par le fournisseur pris en charge par Cloud Native Computing Foundation.
- Normalise la génération et la collecte de données de télémétrie pour les logiciels natifs cloud.
- Fonctionne avec .NET à l’aide des API de métrique .NET.
- Est approuvé par Azure Monitor et de nombreux fournisseurs APM.
Ce tutoriel présente l’une des intégrations disponibles pour les métriques OpenTelemetry à l’aide des projets OSS Prometheus et Grafana . Flux de données des métriques :
Les API de métrique .NET enregistrent les mesures de l’exemple d’application.
La bibliothèque OpenTelemetry s’exécutant dans l’application agrège les mesures.
La bibliothèque d’exportation Prometheus rend les données agrégées disponibles via un point de terminaison de métriques HTTP. « Exporter » est le nom donné par OpenTelemetry aux bibliothèques qui transmettent les données de télémétrie aux back-ends spécifiques au fournisseur.
Un serveur Prometheus :
- Sondage sur le point de terminaison des mesures
- Lit les données
- Stocke les données dans une base de données pour la persistance à long terme. Prometheus désigne la lecture et le stockage de données comme le scraping d'un point de terminaison.
- Peut s’exécuter sur un autre ordinateur
Serveur Grafana :
- Interroge les données stockées dans Prometheus et les affiche sur un tableau de bord de surveillance web.
- Peut s’exécuter sur un autre ordinateur.
Configurer l’exemple d’application pour utiliser l’exportateur Prometheus d’OpenTelemetry
Ajoutez une référence à l’exportateur OpenTelemetry Prometheus à l’exemple d’application :
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
Remarque
Ce tutoriel utilise une version préliminaire de la prise en charge Prometheus d’OpenTelemetry disponible au moment de l’écriture.
Veuillez mettre à jour Program.cs
avec la configuration OpenTelemetry :
using OpenTelemetry;
using OpenTelemetry.Metrics;
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(
name: "hats-sold",
unit: "Hats",
description: "The number of hats sold in our store");
static void Main(string[] args)
{
using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("HatCo.HatStore")
.AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "http://localhost:9184/" })
.Build();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0,1000));
}
}
}
Dans le code précédent :
AddMeter("HatCo.HatStore")
configure OpenTelemetry pour transmettre toutes les métriques collectées par le compteur défini dans l’application.AddPrometheusHttpListener
configure OpenTelemetry à :- Exposer le point de terminaison des mesures de Prometheus sur le port
9184
- Utilisez HttpListener.
- Exposer le point de terminaison des mesures de Prometheus sur le port
Pour plus d’informations sur les options de configuration d’OpenTelemetry, consultez la documentation OpenTelemetry . La documentation OpenTelemetry présente les options d’hébergement des applications ASP.NET.
Exécutez l’application et laissez-la en cours d’exécution afin que les mesures puissent être collectées :
dotnet run
Installer et configurer Prometheus
Suivez les premières étapes de Prometheus pour configurer un serveur Prometheus et confirmez qu’il fonctionne.
Modifiez le fichier de configuration prometheus.yml afin que Prometheus supprime le point de terminaison des métriques que l’exemple d’application expose. Ajoutez le texte en surbrillance suivant dans la scrape_configs
section :
# 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']
Démarrer Prometheus
Rechargez la configuration ou redémarrez le serveur Prometheus.
Vérifiez que OpenTelemetryTest est dans l'état UP sur la page d'état>Cibles du portail Web de Prometheus.
Dans la page Graph (Graphique) du portail Web Prometheus, saisissez
hats
dans la zone de texte Expression et sélectionnezhats_sold_Hats
. Dans l'onglet Graph (Graphique), Prometheus affiche la valeur croissante du compteur « hats-sold » émis par l'application exemple.
Dans l’image précédente, l’heure du graphique est définie sur 5m, soit 5 minutes.
Si le serveur Prometheus n'a pas effectué de scraping de l'application d'exemple depuis longtemps, vous devrez peut-être attendre que les données s'accumulent.
Afficher les métriques sur un tableau de bord Grafana
Suivez les instructions standard pour installer Grafana et la connecter à une source de données Prometheus.
Créez un tableau de bord Grafana en cliquant sur l’icône + dans la barre d’outils de gauche dans le portail web Grafana, puis sélectionnez Tableau de bord. Dans l’éditeur de tableau de bord qui s’affiche, entrez Hats Sold/Sec dans le champ de saisie Titre et rate(hats_sold[5m]) dans le champ d’expression PromQL.
Cliquez sur Appliquer pour enregistrer et afficher le nouveau tableau de bord.
]
Créer un outil de collection personnalisé à l’aide de l’API .NET MeterListener
L’API .NET MeterListener vous permet de créer une logique in-process personnalisée pour observer les mesures enregistrées par System.Diagnostics.Metrics.Meter. Pour obtenir des conseils sur la création d’une logique personnalisée compatible avec l’instrumentation EventCounters plus ancienne, consultez EventCounters.
Modifiez le code de Program.cs
pour utiliser MeterListener :
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(
name: "hats-sold",
unit: "Hats",
description: "The number of hats sold in our store");
static void Main(string[] args)
{
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
meterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);
// Start the meterListener, enabling InstrumentPublished callbacks.
meterListener.Start();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
static void OnMeasurementRecorded<T>(
Instrument instrument,
T measurement,
ReadOnlySpan<KeyValuePair<string, object?>> tags,
object? state)
{
Console.WriteLine($"{instrument.Name} recorded measurement {measurement}");
}
}
La sortie suivante affiche la sortie de l'application avec un rappel personnalisé pour chaque mesure :
> dotnet run
Press any key to exit
hats-sold recorded measurement 978
hats-sold recorded measurement 775
hats-sold recorded measurement 666
hats-sold recorded measurement 66
hats-sold recorded measurement 914
hats-sold recorded measurement 912
...
Explication de l’exemple de code
Les extraits de code de cette section proviennent de l’exemple précédent.
Dans le code mis en surbrillance suivant, une instance du fichier MeterListener est créée pour recevoir des mesures. Le mot clé using
entraîne l'appel de Dispose
lorsque meterListener
sort de la portée.
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
Le code mis en surbrillance suivant configure les instruments dont l’écouteur reçoit les mesures. InstrumentPublished est un délégué appelé lorsqu’un nouvel instrument est créé dans l’application.
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
Le délégué peut examiner l’instrument pour décider s’il faut s’abonner. Par exemple, le délégué peut vérifier le nom, le compteur ou toute autre propriété publique. EnableMeasurementEvents permet de recevoir des mesures à partir de l’instrument spécifié. Code qui obtient une référence à un instrument par une autre approche :
- Ce n’est généralement pas fait.
- Peut invoquer
EnableMeasurementEvents()
à tout moment avec la référence.
Le délégué appelé lorsque les mesures sont reçues d’un instrument est configuré en appelant SetMeasurementEventCallback.
meterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);
// Start the meterListener, enabling InstrumentPublished callbacks.
meterListener.Start();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
static void OnMeasurementRecorded<T>(
Instrument instrument,
T measurement,
ReadOnlySpan<KeyValuePair<string, object?>> tags,
object? state)
{
Console.WriteLine($"{instrument.Name} recorded measurement {measurement}");
}
Le paramètre générique contrôle le type de données de mesure reçu par le rappel. Par exemple, un Counter<int>
génère des int
mesures, un Counter<double>
génère des double
mesures. Les instruments peuvent être créés avec byte
, , short
int
, long
float
, , double
et decimal
types. Nous vous recommandons d’inscrire un rappel pour chaque type de données, sauf si vous avez des connaissances spécifiques au scénario que tous les types de données ne sont pas nécessaires. Faire des appels répétés à SetMeasurementEventCallback
avec des arguments génériques différents peut sembler un peu inhabituel. L’API a été conçue de cette façon pour permettre à un MeterListener
de recevoir des mesures avec une faible surcharge de performance, généralement seulement quelques nanosecondes.
Lorsque MeterListener.EnableMeasurementEvents
est appelé, un objet state
peut être fourni comme l'un des paramètres. L’objet state
est arbitraire. Si vous fournissez un objet d’état dans cet appel, il est stocké avec cet instrument et retourné à vous en tant que state
paramètre dans le rappel. Cela est destiné à la fois comme une commodité et comme optimisation des performances. Souvent, les auditeurs doivent :
- Créez un objet pour chaque instrument qui stocke les mesures en mémoire.
- Avoir du code pour effectuer des calculs sur ces mesures.
Vous pouvez également créer un Dictionary
qui effectue le mappage entre l'instrument et l'objet de stockage, puis le rechercher à chaque mesure. L’utilisation d’un Dictionary
est beaucoup plus lente que l’accès à partir de state
.
meterListener.Start();
Le code précédent lance le MeterListener
qui active les rappels. Le délégué InstrumentPublished
est appelé pour chaque instrument préexistant dans le processus. Les objets Instrument nouvellement créés déclenchent également l'appel de InstrumentPublished
.
using MeterListener meterListener = new MeterListener();
Lorsque l’application est en cours d’écoute, la suppression de l’écouteur arrête le flux des rappels et libère toutes les références internes à l’objet écouteur. Le mot-clé using
utilisé lors de la déclaration meterListener
entraîne l'appel de Dispose
lorsque la variable sort du champ. Veuillez noter que Dispose
garantit uniquement qu'aucun nouvel appel de fonction ne sera lancé. Étant donné que les rappels se produisent sur différents threads, il peut toujours y avoir des rappels en cours après le retour de l’appel Dispose
.
Pour garantir qu’une certaine région de code dans le rappel n’est pas en cours d’exécution et ne s’exécute pas à l’avenir, la synchronisation de threads doit être ajoutée. Dispose
n’inclut pas la synchronisation par défaut, car :
- La synchronisation ajoute une surcharge de performances à chaque rappel de mesure.
MeterListener
est conçu comme une API hautement sensible aux performances.