Lenguaje

Configuración del seguimiento distribuido en .NET

En .NET 11 y versiones posteriores, las API Microsoft.Extensions.Diagnostics.Tracing te permiten registrar instancias ActivityListener y utilizar reglas para seleccionar las instancias ActivitySource y Activity que recibe cada oyente. Defina reglas en el código o cárgelas desde IConfiguration.

Importante

Las reglas de rastreo solo afectan a los oyentes registrados a través de esta infraestructura de rastreo. No afectan a instancias no relacionadas ActivityListener , incluidos los agentes de escucha que los exportadores de telemetría crean y administran. Configure esos listeners o exportadores por separado.

Registrar el rastreo

Las API están disponibles en el Microsoft.Extensions.Diagnostics paquete. Las aplicaciones que hacen referencia al Microsoft.AspNetCore.App framework compartido ya incluyen el ensamblado.

Llama a AddTracing en un IServiceCollection. En el callback:

  • Llama a AddListener para registrar cada oyente. El nombre del agente de escucha identifica el agente de escucha en las reglas de configuración.
  • Configura el muestreo del oyente y los delegados de notificación a través de ActivityListenerBuilder. La infraestructura de rastreo es propietaria de ShouldListenTo, de las suscripciones de origen y del ciclo de vida del oyente.
  • Llame a AddConfiguration con la sección de configuración que contiene las reglas. Para una sección denominada Tracing, pase configuration.GetSection("Tracing").

En el ejemplo completo se muestran las tres llamadas. Un host de .NET activa las suscripciones de seguimiento cuando se inicia el host. Si utilizas la inyección de dependencias sin un host, resuelve el ActivitySourceFactory registrado para construir los oyentes y activar sus suscripciones. El ejemplo completo resuelve la fábrica directamente.

Configurar el seguimiento

Establezca reglas de seguimiento a través de la configuración o en el código. Si ninguna regla coincide con un listener, un origen, una operación y un ámbito, el seguimiento permanece deshabilitado para esa combinación.

Configurar el seguimiento sin código

En el caso de las aplicaciones que usan la configuración, agregue una Tracing sección a appsettings.json u otro proveedor de configuración. A continuación, pase esa sección a AddConfiguration:

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

En el ejemplo siguiente se muestran las secciones de reglas admitidas y los niveles de regla:

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

Agregue reglas directamente debajo de una sección EnabledTracing, EnabledGlobalTracing o EnabledLocalTracing. No añadas un nivel Rules.

Secciones de reglas

Elige una sección de reglas en función del ámbito de la fuente y de si la regla se dirige a un único oyente:

Section Oyentes coincidentes Fuentes de actividad coincidentes
EnabledTracing Todos los oyentes registrados. Orígenes globales y locales.
EnabledGlobalTracing Todos los oyentes registrados. Solo fuentes globales.
EnabledLocalTracing Todos los oyentes registrados. Solo fuentes locales.
{Listener}:EnabledTracing El oyente nombrado. Orígenes globales y locales.
{Listener}:EnabledGlobalTracing El oyente nombrado. Solo fuentes globales.
{Listener}:EnabledLocalTracing El oyente nombrado. Solo fuentes locales.

Los nombres de los oyentes coinciden con los nombres pasados a AddListener. Los nombres de sección y los nombres del listener no distinguen entre mayúsculas y minúsculas.

Niveles de regla

En cualquier sección de regla, use una de las siguientes formas de clave:

Forma clave Nivel de regla Match
Default Predeterminada. Todas las fuentes y operaciones.
{SourceName} Origen de la actividad. Todas las operaciones de las fuentes coincidentes.
{SourceName}:Default Origen de la actividad. Todas las operaciones de las fuentes coincidentes. Este formulario permite que una fuente también contenga reglas de operación.
{SourceName}:{OperationName} Operación. La operación especificada de las fuentes coincidentes.

Establezca cada valor hoja en true para habilitar la coincidencia o false para deshabilitarlo. Por ejemplo, la configuración anterior:

  • Deshabilita el seguimiento de forma predeterminada.
  • Habilita los orígenes cuyos nombres comienzan por Contoso.
  • Habilita Contoso.Orders, pero deshabilita su HealthCheck operación.
  • Habilita un patrón de origen que comienza con Contoso. y termina con .Storage.
  • Añade reglas que se aplican únicamente a fuentes globales, fuentes locales o al oyente denominado Console.

Utiliza Default como hoja booleana. Si Default contiene elementos secundarios de la operación, la configuración trata Default como un nombre literal de origen de actividad.

Configurar el seguimiento con código

Llame a EnableTracing y a ITracingBuilder en el AddTracing pasado a DisableTracing.

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

Omite sourceName, operationName o listenerName para que coincidan todos los valores de ese nivel. De forma predeterminada, una regla programática se aplica a orígenes globales y locales. Pasa Global, Local o ambos a través del argumento scopes para restringir la regla.

Las reglas de configuración y las reglas programáticas forman un conjunto de reglas ordenado. Si hay conflictos entre reglas igualmente específicas, prevalece la última regla añadida. Por lo tanto, el orden de las llamadas en la AddTracing devolución de llamada es importante cuando AddConfiguration, EnableTracingy DisableTracing agregan reglas igualmente específicas.

Coincidencia de nombres de fuentes de actividad

Los nombres de origen, los nombres de operación y los nombres del agente de escucha usan la comparación ordinal que no distingue mayúsculas de minúsculas. Las reglas de nombre de origen admiten estas formas de coincidencia:

  • Un nombre de fuente vacío coincide con todas las fuentes.
  • Un nombre de fuente sin comodín coincide por prefijo. Por ejemplo, Contoso coincide con Contoso.Orders y ContosoPayments; el comparador no requiere un separador después del prefijo.
  • Un nombre de fuente con un comodín * coincide con un prefijo y un sufijo. Por ejemplo, Contoso.*.Storage coincide con Contoso.Orders.Storage, pero no coincide con Contoso.Orders.Api.
  • Un nombre de fuente * coincide con todas las fuentes.

Los nombres de operación coinciden exactamente. No usan la coincidencia por prefijo ni la coincidencia de caracteres comodín.

Aplicar la prioridad de las reglas

Para cada combinación de oyente, fuente, operación y ámbito, la infraestructura de rastreo elige una regla que coincida. Compara las reglas de coincidencia en este orden:

  • Una regla específica del listener tiene prioridad sobre una regla para todos los listeners.
  • Una regla de origen tiene prioridad sobre una regla predeterminada. Si dos expresiones de origen coinciden, la expresión más larga tiene prioridad. La comparación usa la longitud de la expresión, incluido el comodín *.
  • Una regla de operación tiene prioridad sobre una regla de nivel de origen.
  • Una regla solo global o solo local tiene prioridad sobre una regla que abarca ambos ámbitos.
  • La última regla tiene prioridad cuando todos los factores anteriores son iguales.

La comparación se detiene en la primera diferencia. Por ejemplo, una regla predeterminada específica de un oyente tiene prioridad sobre una regla específica de una fuente que se aplica a todos los oyentes, ya que la especificidad del oyente se evalúa en primer lugar.

Las reglas de operación también controlan las suscripciones de origen. Un oyente se suscribe a una fuente que está desactivada por defecto cuando una regla de operación habilita al menos una operación de esa fuente. A continuación, el oyente devuelve None y omite sus llamadas de retorno para las operaciones desactivadas.

Elección de orígenes de actividad globales o locales

La infraestructura de seguimiento distingue dos ámbitos de origen de actividad:

  • Una fuente global es un ActivitySource creado a través de su compilador. Las reglas EnabledGlobalTracing se aplican a estas fuentes.
  • Una fuente local es una ActivitySource creada por la ActivitySourceFactory resuelta a partir de la inyección de dependencias. Las reglas EnabledLocalTracing se aplican a las fuentes creadas por esa fábrica.

Utiliza Create cuando desees que el contenedor de inyección de dependencias administre la fuente y sus oyentes de rastreo. Los oyentes de una fábrica ignoran las fuentes locales creadas por otra fábrica. Las reglas de EnabledTracing se aplican a ambos tipos de fuentes.

Estos ámbitos restringen únicamente los oyentes que AddTracing registra. Un ActivityListener independiente usa sus propias ShouldListenTo y callbacks de muestreo, incluso para un origen de actividad creado por ActivitySourceFactory.

Recargar la configuración de seguimiento

AddConfiguration se suscribe al token de cambio de la configuración proporcionada. Cuando un proveedor de configuración admite la recarga e informa de un cambio, la infraestructura de seguimiento:

  • Vuelve a generar el conjunto de reglas.
  • Actualiza las suscripciones a fuentes de cada oyente registrado.
  • Aplica las reglas actualizadas a las actividades posteriores.

La aplicación puede seguir usando las mismas ActivitySource instancias después de una recarga. Las actividades posteriores usan las reglas actualizadas.

Para un proveedor mutable que no notifica los cambios automáticamente, actualice la configuración y llame a Reload. En el ejemplo completo se usa este enfoque con el proveedor de configuración en memoria.

Administrar la configuración no válida

La configuración de seguimiento analiza los valores con TryParse. Acepta true y false sin tener en cuenta el caso y permite espacios en blanco circundantes. No acepta 1, 0, yeso on.

El cargador de configuración omite silenciosamente un valor hoja que no es un valor booleano válido. También omite secciones desconocidas o con formato incorrecto que no coinciden con el esquema admitido. Compruebe cuidadosamente los nombres de clave porque estos casos no generan una excepción.

Una expresión de origen puede contener como máximo un * carácter comodín. Una regla con más de un carácter comodín lanza un ArgumentException cuando la regla se materializa, ya sea durante el inicio de la aplicación o después de la recarga de configuración. En el caso de las reglas programáticas, None también provoca un ArgumentOutOfRangeException.

Ejecución del ejemplo

La siguiente aplicación de consola .NET 11 crea una operación habilitada y una operación deshabilitada. A continuación, actualiza la regla de la operación deshabilitada, llama a Reload e inicia de nuevo la operación a través del mismo ActivitySource local.

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

Los ejemplos de C# y Visual Basic producen el mismo resultado:

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

Consulte también