Lingua

Configurare il tracciamento distribuito in .NET

In .NET 11 e versioni successive, le Microsoft.Extensions.Diagnostics.Tracing API consentono di registrare le istanze ActivityListener e usare regole per selezionare le istanze ActivitySource e Activity ricevute da ogni listener. Definire le regole nel codice o caricarle da IConfiguration.

Importante

Le regole di tracciamento influiscono solo sui listener registrati tramite questa infrastruttura di tracciamento. Non influiscono sulle istanze non correlate ActivityListener , inclusi i listener creati e gestiti dagli esportatori di dati di telemetria. Configurate separatamente questi listener o exporter.

Registrare il tracciamento

Le API sono disponibili nel Microsoft.Extensions.Diagnostics pacchetto. Le app che fanno riferimento al Microsoft.AspNetCore.App framework condiviso includono già l'assembly.

Chiama AddTracing su un IServiceCollection. Nella funzione di callback:

  • Chiamare AddListener per registrare ciascun listener. Il nome del listener identifica il listener nelle regole di configurazione.
  • Configurare i delegati di campionamento e notifica del listener tramite ActivityListenerBuilder. L'infrastruttura di traccia gestisce ShouldListenTo, le sottoscrizioni di origine e il ciclo di vita del listener.
  • Chiamare AddConfiguration con la sezione di configurazione che contiene le regole. Per una sezione denominata Tracing, passare configuration.GetSection("Tracing").

L'esempio completo mostra tutte e tre le chiamate. Un host .NET attiva le sottoscrizioni di traccia all'avvio dell'host. Se si usa l'iniezione delle dipendenze senza un host, risolvere il servizio registrato ActivitySourceFactory per costruire i listener e attivare le sottoscrizioni. L'esempio completo risolve direttamente la factory.

Configurare il tracciamento

Imposta le regole di tracciamento tramite configurazione o nel codice. Se nessuna regola corrisponde a un listener, una sorgente, un'operazione e un ambito, il tracciamento rimane disabilitato per tale combinazione.

Configurare il tracciamento senza codice

Per le app che usano la configurazione, aggiungere una Tracing sezione a appsettings.json o a un altro provider di configurazione. Quindi, passa quella sezione a AddConfiguration:

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

L'esempio seguente mostra le sezioni e i livelli di regola supportati:

{
  "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
        }
      }
    }
  }
}

Aggiungere regole direttamente in una sezione EnabledTracing, EnabledGlobalTracing o EnabledLocalTracing. Non aggiungere un Rules livello.

Sezioni della regola

Scegliere una sezione della regola in base all'ambito sorgente e se la regola è destinata a un listener di rete:

Sezione Abbinamento listener Origini delle attività corrispondenti
EnabledTracing Tutti i listener registrati. Origini globali e locali.
EnabledGlobalTracing Tutti i listener registrati. Solo sorgenti globali.
EnabledLocalTracing Tutti i listener registrati. Solo fonti locali.
{Listener}:EnabledTracing Il listener denominato. Origini globali e locali.
{Listener}:EnabledGlobalTracing Il listener con nome. Solo fonti globali.
{Listener}:EnabledLocalTracing Il listener denominato. Solo fonti locali.

I nomi del listener corrispondono ai nomi passati a AddListener. I nomi di sezione e i nomi del listener non fanno distinzione tra maiuscole e minuscole.

Livelli delle regole

In qualsiasi sezione della regola usare una delle seguenti forme di chiave:

Modulo chiavi Livello della regola Match
Default Default. Ogni sorgente e operazione.
{SourceName} Origine dell'attività Ogni operazione da sorgenti corrispondenti.
{SourceName}:Default Origine dell'attività. Ogni operazione dalle origini corrispondenti. Questo modulo consente a un'origine dati di contenere anche regole operative.
{SourceName}:{OperationName} Operazione. Operazione denominata dalle fonti corrispondenti.

Impostare ogni valore foglia su true per abilitare la corrispondenza o false per disabilitarla. Ad esempio, la configurazione precedente:

  • Disabilita il tracciamento per impostazione predefinita.
  • Abilita le origini dati i cui nomi iniziano con Contoso.
  • Abilita Contoso.Orders, ma ne disabilita il suo funzionamento HealthCheck.
  • Abilita un modello di origine che inizia con Contoso. e termina con .Storage.
  • Aggiunge regole applicabili solo a origini dati globali, origini dati locali o al listener denominato Console.

Usare Default come foglia booleana. Se Default contiene elementi figlio dell'operazione, la configurazione considera Default come un nome letterale dell'origine dell'attività.

Configurare il tracciamento con il codice

Chiamare EnableTracing e DisableTracing su ITracingBuilder passato a AddTracing.

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

Omettere sourceName, operationName o listenerName per corrispondere a tutti i valori a tale livello. Per impostazione predefinita, una regola programmatica si applica alle origini globali e locali. Passare Global, Localo entrambi tramite l'argomento scopes per restringere la regola.

Le regole di configurazione e le regole a livello di codice formano un set di regole ordinato. Se regole ugualmente specifiche sono in conflitto, prevale la regola aggiunta per ultima. L'ordine delle chiamate nel callback AddTracing è quindi importante quando AddConfiguration, EnableTracing e DisableTracing aggiungono regole ugualmente specifiche.

Abbina i nomi delle fonti di attività

I nomi delle sorgenti, i nomi delle operazioni e i nomi del listener usano un confronto ordinale senza distinzione tra maiuscole e minuscole. Le regole del nome di origine supportano queste forme di corrispondenza:

  • Un nome di origine vuoto corrisponde a ogni origine.
  • Un nome di origine senza caratteri jolly corrisponde per prefisso. Ad esempio, Contoso corrisponde a Contoso.Orders e ContosoPayments; il matcher non richiede un separatore dopo il prefisso.
  • Un nome di origine con un * carattere jolly corrisponde a un modello con prefisso e suffisso. Ad esempio, Contoso.*.Storage corrisponde a Contoso.Orders.Storage, ma non a Contoso.Orders.Api.
  • Un nome di origine pari a * corrisponde a ogni origine.

I nomi delle operazioni corrispondono esattamente. Non utilizzano la corrispondenza per prefisso o la corrispondenza con wildcard.

Applica la priorità della regola

Per ogni listener, sorgente, operazione e combinazione di ambito, l'infrastruttura di traccia sceglie una regola corrispondente. Confronta le regole di corrispondenza in questo ordine:

  • Una regola specifica del listener ha la precedenza su una regola per tutti i listener.
  • Una regola di origine ha la precedenza su una regola predefinita. Se due espressioni di origine corrispondono, l'espressione più lunga ha la precedenza. Il confronto usa la lunghezza dell'espressione, incluso un carattere jolly *.
  • Una regola dell'operazione ha la precedenza su una regola a livello di sorgente.
  • Una regola solo globale o solo locale ha la precedenza su una regola che copre entrambi gli ambiti.
  • L'ultima regola ha la precedenza quando tutti i fattori precedenti sono uguali.

Il confronto si interrompe alla prima differenza. Ad esempio, una regola predefinita specifica del listener ha la precedenza su una regola specifica dell'origine che si applica a tutti i listener perché la specificità del listener viene valutata per prima.

Le regole operative controllano anche le sottoscrizioni di origine. Un listener si iscrive a un'origine dati disabilitata per impostazione predefinita quando una regola di operazione abilita almeno un'operazione da tale origine dati. Il listener restituisce None e ignora i callback per le operazioni disabilitate.

Scegliere fonti di attività globali o locali

L'infrastruttura di traccia distingue due ambiti dell'origine dell'attività:

  • Una sorgente ActivitySource è un creato tramite il relativo costruttore. EnabledGlobalTracing le regole si applicano a queste fonti.
  • Un'origine locale è un oggetto ActivitySource creato tramite l'ActivitySourceFactory iniezione delle dipendenze risolta. EnabledLocalTracing le regole si applicano alle sorgenti create da tale fabbrica.

Usare Create quando si vuole che il contenitore di dependency injection gestisca l'origine e i relativi listener di tracciamento. I listener di una factory ignorano le sorgenti locali create da una factory diversa. Le regole in EnabledTracing si applicano a entrambi i tipi di sorgente.

Questi ambiti limitano solo i listener che AddTracing registra. Un oggetto indipendente ActivityListener usa i propri ShouldListenTo e callback di campionamento, anche per un'origine attività creata da ActivitySourceFactory.

Ricarica la configurazione del tracciamento

AddConfiguration si sottoscrive al token di modifica della configurazione fornita. Quando un provider di configurazione supporta il ricaricamento e segnala una modifica, l'infrastruttura di tracciamento:

  • Ricompila il set di regole.
  • Aggiorna le sottoscrizioni di origine di ogni listener registrato.
  • Applica le regole aggiornate alle attività successive.

L'app può continuare a usare le stesse ActivitySource istanze dopo un ricaricamento. Le attività successive usano le regole aggiornate.

Per un provider modificabile che non segnala automaticamente le modifiche, aggiornare la configurazione e chiamare Reload. L'esempio completo usa questo approccio con il provider di configurazione in memoria.

Gestisci la configurazione non valida

La configurazione di tracciamento esegue il parsing dei valori con TryParse. Accetta true e false senza distinzione tra maiuscole e minuscole e consente spazi vuoti circostanti. Non accetta 1, 0, yeso on.

Il caricatore di configurazione ignora senza segnalarlo un valore foglia che non è un valore booleano valido. Ignora anche sezioni sconosciute o in formato non valido che non corrispondono allo schema supportato. Controllare attentamente i nomi delle chiavi perché questi casi non generano un'eccezione.

Un'espressione di origine può contenere al massimo un * carattere jolly. Una regola con più caratteri jolly genera un'eccezione ArgumentException quando la regola viene materializzata, durante l'avvio dell'app o dopo il ricaricamento della configurazione. Per le regole programmatiche, None genera anche un ArgumentOutOfRangeException.

Esegui l'esempio

L'app console seguente .NET 11 crea un'operazione abilitata e un'operazione disabilitata. Aggiorna quindi la regola dell'operazione disabilitata, chiama Reloade avvia nuovamente l'operazione tramite lo stesso oggetto locale 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

Gli esempi C# e Visual Basic producono lo stesso risultato:

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

Vedere anche