Langue

Configurer le suivi distribué dans .NET

Dans .NET 11 et versions ultérieures, les API Microsoft.Extensions.Diagnostics.Tracing vous permettent d’enregistrer des instances ActivityListener et d’utiliser des règles pour sélectionner les instances ActivitySource et Activity que chaque écouteur reçoit. Définissez des règles dans le code ou chargez-les à partir de IConfiguration.

Important

Les règles de traçage affectent uniquement les écouteurs d’événements inscrits via cette infrastructure de traçage. Ils n’affectent pas les instances non liées ActivityListener , y compris les écouteurs que les exportateurs de télémétrie créent et gèrent. Configurez ces listeners ou exportateurs séparément.

Enregistrer le traçage

Les API sont disponibles dans le Microsoft.Extensions.Diagnostics package. Les applications qui référencent le framework Microsoft.AspNetCore.App partagé incluent déjà l’assembly.

Appelez AddTracing sur un IServiceCollection. Dans le callback :

  • Appelez AddListener pour inscrire chaque écouteur d’événement. Le nom du listener identifie le listener dans les règles de configuration.
  • Configurez les délégués d’échantillonnage et de notification de l’écouteur via ActivityListenerBuilder. L’infrastructure de suivi gère les ShouldListenToabonnements sources et la durée de vie de l’écouteur.
  • Appelez AddConfiguration avec la section de configuration qui contient les règles. Pour une section nommée Tracing, passez configuration.GetSection("Tracing").

L’exemple complet affiche les trois appels. Un hôte .NET active les abonnements de traçage au démarrage de l’hôte. Si vous utilisez l’injection de dépendances sans hôte, résolvez le service enregistré ActivitySourceFactory pour construire les écouteurs et activer leurs abonnements. L’exemple complet résout directement la factory.

Configurer le traçage

Définissez des règles de traçage via la configuration ou dans le code. Si aucune règle ne correspond à un listener, une source, une opération et une étendue, le suivi reste désactivé pour cette combinaison.

Configurer le traçage sans code

Pour les applications qui utilisent la configuration, ajoutez une Tracing section à appsettings.json ou à un autre fournisseur de configuration. Passez ensuite cette section à AddConfiguration:

tracing.AddConfiguration(configuration.GetSection("Tracing"));

L’exemple suivant montre les sections de règle prises en charge et les niveaux de règle :

{
  "Tracing": {
    "EnabledTracing": {
      "Default": false,
      "Contoso": true,
      "Contoso.Orders": {
        "Default": true,
        "HealthCheck": false
      },
      "Contoso.*.Storage": true
    },
    "EnabledGlobalTracing": {
      "System.Net.Http": true
    },
    "EnabledLocalTracing": {
      "Contoso.Workers": true
    },
    "Console": {
      "EnabledLocalTracing": {
        "Contoso.Orders": {
          "Submit": false
        }
      }
    }
  }
}

Ajoutez des règles directement sous une section EnabledTracing, EnabledGlobalTracing ou EnabledLocalTracing. N’ajoutez pas de niveau Rules.

Sections des règles

Choisissez une section de règle en fonction de l’étendue source et selon que la règle cible un seul écouteur :

Rubrique Listeners correspondants Sources d’activité associées
EnabledTracing Tous les listeners inscrits. Sources globales et locales.
EnabledGlobalTracing Tous les auditeurs inscrits. Sources mondiales uniquement.
EnabledLocalTracing Tous les auditeurs inscrits. Sources locales uniquement.
{Listener}:EnabledTracing Le listener nommé. Sources globales et locales.
{Listener}:EnabledGlobalTracing Listener nommé. Uniquement les sources mondiales.
{Listener}:EnabledLocalTracing Le listener nommé. Sources locales uniquement.

Les noms des écouteurs correspondent aux noms passés à AddListener. Les noms de section et les noms d’écouteur ne sont pas sensibles à la casse.

Niveaux de règle

Sous n’importe quelle section de règle, utilisez l’une des formes clés suivantes :

Formulaire de clé Niveau de règle Match
Default Default. Toutes les sources et opérations.
{SourceName} Source d’activité. Chaque opération à partir de sources correspondantes.
{SourceName}:Default Source d’activité. Chaque opération à partir de sources correspondantes. Ce formulaire permet à une source de contenir également des règles d’opération.
{SourceName}:{OperationName} Opération. Opération nommée provenant des sources correspondantes.

Définissez chaque valeur de feuille à true pour activer la correspondance ou à false pour la désactiver. Par exemple, la configuration précédente :

  • Désactive le suivi par défaut.
  • Active les sources dont les noms commencent par Contoso.
  • Active Contoso.Orders, mais désactive son fonctionnement HealthCheck.
  • Active un modèle source qui commence par Contoso. et se termine par .Storage.
  • Ajoute des règles qui s’appliquent uniquement aux sources globales, aux sources locales ou au listener nommé Console.

Utilisez Default comme feuille booléenne. Si Default contient des éléments enfants d’opération, la configuration traite Default comme un nom de source d’activité littéral.

Configurer le suivi avec du code

Appelez EnableTracing et ITracingBuilder sur le AddTracing passé à DisableTracing.

tracing.EnableTracing(sourceName: "Contoso");
tracing.DisableTracing(
    sourceName: "Contoso.Orders",
    operationName: "HealthCheck");

Omettez sourceName, operationNameou listenerName pour faire correspondre toutes les valeurs à ce niveau. Par défaut, une règle programmatique s’applique aux sources globales et locales. Passez Global, Local ou les deux via l’argument scopes pour affiner la règle.

Les règles de configuration et les règles de programmation forment un ensemble de règles ordonné. Si des règles tout aussi spécifiques sont en conflit, la dernière règle ajoutée l’emporte. L’ordre des appels dans le rappel AddTracing importe donc quand AddConfiguration, EnableTracing et DisableTracing ajoutent des règles tout aussi spécifiques.

Mettre en correspondance les noms de source d’activité

Les noms sources, les noms d’opérations et les noms d’écouteur utilisent une comparaison ordinale sans respect de la casse. Les règles de nom de source prennent en charge les formes de correspondance suivantes :

  • Un nom source vide correspond à chaque source.
  • Un nom source sans caractère générique correspond par préfixe. Par exemple, Contoso correspond à Contoso.Orders et à ContosoPayments ; le moteur de correspondance ne nécessite pas de séparateur après le préfixe.
  • Un nom de source avec un * caractère générique correspond à un nom avec un préfixe et un suffixe. Par exemple, Contoso.*.Storage correspond à Contoso.Orders.Storage, mais pas Contoso.Orders.Api.
  • Un nom de source * correspond à toutes les sources.

Les noms des opérations correspondent exactement. Ils n’utilisent pas de correspondance par préfixe ou avec caractères génériques.

Appliquer la priorité des règles

Pour chaque combinaison d’écouteur, de source, d’opération et de portée, l’infrastructure de suivi choisit une règle correspondante. Il compare les règles de correspondance dans cet ordre :

  • Une règle spécifique à un programme d’écoute est prioritaire sur une règle pour tous les programmes d’écoute.
  • Une règle source est prioritaire sur une règle par défaut. Si deux expressions sources correspondent, l’expression plus longue est prioritaire. La comparaison utilise la longueur de l’expression, y compris un caractère générique *.
  • Une règle d’opération est prioritaire sur une règle de niveau source.
  • Une règle globale uniquement ou locale uniquement est prioritaire sur une règle qui couvre les deux étendues.
  • La dernière règle est prioritaire lorsque tous les facteurs précédents sont égaux.

La comparaison s’arrête à la première différence. Par exemple, une règle par défaut spécifique à un listener est prioritaire sur une règle spécifique à la source qui s’applique à tous les listeners, car la spécificité du listener est évaluée en premier.

Les règles d’opération contrôlent également les abonnements source. Un écouteur s’abonne à une source, désactivée par défaut, lorsqu’une règle d’opération active au moins une opération provenant de cette source. L’écouteur retourne None puis ignore ses callbacks pour les opérations désactivées.

Choisir des sources d’activité globales ou locales

L’infrastructure de suivi distingue deux portées des sources d’activité :

  • Une source globale est une ActivitySource source créée par le biais de son constructeur. EnabledGlobalTracing ces règles s’appliquent à ces sources.
  • Une source locale est un ActivitySource créé par le ActivitySourceFactory résolu par injection de dépendances. EnabledLocalTracing les règles s’appliquent aux sources créées par cette factory.

Utilisez Create quand vous souhaitez que le conteneur d’injection de dépendances gère la source et ses écouteurs de suivi. Les listeners d’une factory ignorent les sources locales créées par une autre factory. Les règles de EnabledTracing s’appliquent aux deux types de source.

Ces étendues limitent uniquement les écouteurs que AddTracing enregistre. Un ActivityListener indépendant utilise ses propres ShouldListenTo et fonctions de rappel d’échantillonnage, même pour une source d’activité créée par ActivitySourceFactory.

Recharger la configuration du traçage

AddConfiguration s’abonne au jeton de changement de la configuration fournie. Lorsqu’un fournisseur de configuration prend en charge le rechargement et signale une modification, l’infrastructure de suivi :

  • Reconstruit le jeu de règles.
  • Actualise les abonnements sources de chaque observateur inscrit.
  • Applique les règles mises à jour aux activités suivantes.

L’application peut continuer à utiliser les mêmes ActivitySource instances après un rechargement. Les activités suivantes utilisent les règles mises à jour.

Pour un fournisseur mutable qui ne signale pas automatiquement les modifications, mettez à jour la configuration et appelez Reload. L’exemple complet utilise cette approche avec le fournisseur de configuration en mémoire.

Gérer la configuration non valide

La configuration du traçage interprète les valeurs avec TryParse. Il accepte true et false sans égard à la casse et autorise les espaces blancs environnants. Cela n’accepte pas 1, 0, yes, ou on.

Le chargeur de configuration ignore silencieusement une valeur feuille qui n’est pas un booléen valide. Il ignore également les sections inconnues ou incorrectes qui ne correspondent pas au schéma pris en charge. Vérifiez attentivement les noms de clés, car ces cas ne produisent pas d’exception.

Une expression source peut contenir au plus un * caractère générique. Une règle avec plusieurs caractères génériques génère une ArgumentException lorsque la règle est matérialisée, soit au démarrage de l’application, soit après le rechargement de la configuration. Pour les règles programmatiques, None provoque également un ArgumentOutOfRangeException.

Exécuter l’exemple

L’application console .NET 11 suivante crée une opération activée et une opération désactivée. Il met ensuite à jour la règle de l’opération désactivée, appelle Reload et redémarre l’opération par le même élément local ActivitySource.

using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Tracing;

IConfigurationRoot configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["Tracing:EnabledTracing:Default"] = "false",
        ["Tracing:EnabledTracing:Contoso.Orders:Default"] = "true",
        ["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "false",
    })
    .Build();

ServiceCollection services = new();
services.AddTracing(tracing =>
{
    tracing.AddListener("Console", listener =>
    {
        listener.Sample = static (ref ActivityCreationOptions<ActivityContext> _) =>
            ActivitySamplingResult.AllData;
        listener.SampleUsingParentId = static (ref ActivityCreationOptions<string> _) =>
            ActivitySamplingResult.AllData;
        listener.ActivityStarted = activity =>
            Console.WriteLine($"Listener started: {activity.OperationName}");
    });
    tracing.AddConfiguration(configuration.GetSection("Tracing"));
});

using ServiceProvider serviceProvider = services.BuildServiceProvider();
ActivitySourceFactory factory =
    serviceProvider.GetRequiredService<ActivitySourceFactory>();
using ActivitySource source = factory.Create("Contoso.Orders");

Console.WriteLine("Before reload:");
WriteResult(source, "EnabledOperation");
WriteResult(source, "DisabledOperation");

configuration["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "true";
configuration.Reload();

Console.WriteLine("After reload:");
WriteResult(source, "DisabledOperation");

static void WriteResult(ActivitySource source, string operationName)
{
    using Activity? activity = source.StartActivity(operationName);
    string state = activity is null ? "disabled" : "enabled";
    Console.WriteLine($"{operationName}: {state}");
}
Imports System.Diagnostics
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Diagnostics.Tracing

Module Program
    Sub Main()
        Dim initialData As New Dictionary(Of String, String) From {
            {"Tracing:EnabledTracing:Default", "false"},
            {"Tracing:EnabledTracing:Contoso.Orders:Default", "true"},
            {"Tracing:EnabledTracing:Contoso.Orders:DisabledOperation", "false"}
        }

        Dim configuration As IConfigurationRoot =
            New ConfigurationBuilder().AddInMemoryCollection(initialData).Build()

        Dim services As New ServiceCollection()
        services.AddTracing(
            Sub(tracing)
                tracing.AddListener(
                    "Console",
                    Sub(listener)
                        listener.Sample = AddressOf SampleActivity
                        listener.SampleUsingParentId = AddressOf SampleActivityUsingParentId
                        listener.ActivityStarted =
                            Sub(activity) Console.WriteLine(
                                $"Listener started: {activity.OperationName}")
                    End Sub)
                tracing.AddConfiguration(configuration.GetSection("Tracing"))
            End Sub)

        Using serviceProvider As ServiceProvider = services.BuildServiceProvider()
            Dim factory As ActivitySourceFactory =
                serviceProvider.GetRequiredService(Of ActivitySourceFactory)()

            Using source As ActivitySource = factory.Create("Contoso.Orders")
                Console.WriteLine("Before reload:")
                WriteResult(source, "EnabledOperation")
                WriteResult(source, "DisabledOperation")

                configuration(
                    "Tracing:EnabledTracing:Contoso.Orders:DisabledOperation") = "true"
                configuration.Reload()

                Console.WriteLine("After reload:")
                WriteResult(source, "DisabledOperation")
            End Using
        End Using
    End Sub

    Private Function SampleActivity(
        ByRef options As ActivityCreationOptions(Of ActivityContext)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Function SampleActivityUsingParentId(
        ByRef options As ActivityCreationOptions(Of String)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Sub WriteResult(source As ActivitySource, operationName As String)
        Using activity As Activity = source.StartActivity(operationName)
            Dim state As String = If(activity Is Nothing, "disabled", "enabled")
            Console.WriteLine($"{operationName}: {state}")
        End Using
    End Sub
End Module

Les exemples C# et Visual Basic produisent le même résultat :

Before reload:
Listener started: EnabledOperation
EnabledOperation: enabled
DisabledOperation: disabled
After reload:
Listener started: DisabledOperation
DisabledOperation: enabled

Voir également :