Idioma

Configurar o rastreamento distribuído no .NET

No .NET 11 e posteriores, as APIs Microsoft.Extensions.Diagnostics.Tracing permitem registrar instâncias ActivityListener e usar regras para selecionar as instâncias ActivitySource e Activity recebidas por ouvinte. Definir regras no código ou carregá-las de IConfiguration.

Importante

As regras de rastreamento afetam somente os ouvintes registrados por meio dessa infraestrutura de rastreamento. Elas não afetam instâncias não relacionadas ActivityListener, incluindo listeners que os exportadores de telemetria criam e gerenciam. Configure esses listeners ou exportadores separadamente.

Registrar rastreio

As APIs estão disponíveis no Microsoft.Extensions.Diagnostics pacote. Os aplicativos que fazem referência ao Microsoft.AspNetCore.App framework compartilhado já incluem o assembly.

Chame AddTracing em um IServiceCollection. No retorno de chamada:

  • Chame AddListener para registrar cada ouvinte. O nome do listener identifica o listener nas regras de configuração.
  • Configure os delegados de amostragem e notificação do ouvinte por meio de ActivityListenerBuilder. A infraestrutura de rastreamento é responsável por ShouldListenTo, assinaturas de origem e pelo ciclo de vida do listener.
  • Invoque AddConfiguration com a seção de configuração que contém as regras. Para uma seção chamada Tracing, passe configuration.GetSection("Tracing").

O exemplo completo mostra todas as três chamadas. Um host .NET ativa as assinaturas de rastreamento quando o host é iniciado. Se você usar a injeção de dependência sem um host, resolva o ActivitySourceFactory registrado para construir os ouvintes e ativar as assinaturas. A amostra completa resolve diretamente o alocador.

Configurar o rastreamento

Defina regras de rastreamento por meio da configuração ou no código. Se nenhuma regra corresponder a um ouvinte, origem, operação e escopo, o rastreamento permanecerá desabilitado para essa combinação.

Configurar o rastreamento sem código

Para aplicativos que usam a configuração, adicione uma Tracing seção ao appsettings.json ou a outro provedor de configuração. Em seguida, passe essa seção para AddConfiguration:

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

O exemplo a seguir mostra as seções de regra e os níveis de regra suportados:

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

Adicione regras diretamente sob uma seção EnabledTracing, EnabledLocalTracing ou EnabledGlobalTracing. Não adicione um Rules nível.

Seções da regra

Escolha uma seção de regra com base no escopo de origem e se a regra visa a um ouvinte:

Seção Ouvintes compatíveis Fontes de atividades compatíveis
EnabledTracing Todos os ouvintes registrados. Fontes globais e locais.
EnabledGlobalTracing Todos os ouvintes registrados. Somente fontes globais.
EnabledLocalTracing Todos os ouvintes registrados. Somente fontes locais.
{Listener}:EnabledTracing O ouvinte nomeado. Fontes globais e locais.
{Listener}:EnabledGlobalTracing O ouvinte nomeado. Somente fontes globais.
{Listener}:EnabledLocalTracing O ouvinte nomeado. Somente fontes locais.

Os nomes dos ouvintes correspondem aos nomes passados para AddListener. Nomes de seção e nomes de ouvinte não diferenciam maiúsculas de minúsculas.

Níveis de regra

Em qualquer seção de regra, use um dos seguintes formatos de chave:

Formulário de chave Nível da regra Match
Default Padrão. Cada fonte e operação.
{SourceName} Origem da atividade. Cada operação de fontes correspondentes.
{SourceName}:Default Origem da atividade. Cada operação de fontes correspondentes. Esse formulário permite que uma fonte também contenha regras de operação.
{SourceName}:{OperationName} Operação. A operação nomeada das fontes correspondentes.

Defina cada valor folha para true habilitar a correspondência ou para false desabilitá-la. Por exemplo, a configuração anterior:

  • Desabilita o rastreamento por padrão.
  • Habilita origens cujos nomes começam com Contoso.
  • Habilita Contoso.Orders, mas desabilita a operação HealthCheck.
  • Habilita um padrão de origem que começa com Contoso. e termina com .Storage.
  • Adiciona regras que se aplicam somente a fontes globais, fontes locais ou ao ouvinte chamado Console.

Use Default como uma folha Booliana. Se Default contiver filhos de operação, a configuração tratará Default como um nome literal de fonte de atividade.

Configurar o rastreamento com código

Chame EnableTracing e DisableTracing no ITracingBuilder passado para AddTracing.

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

Omita sourceName, operationName ou listenerName para comparar todos os valores nesse nível. Por padrão, uma regra programática se aplica a fontes globais e locais. Passe Global, Localou ambos por meio do scopes argumento para restringir a regra.

Regras de configuração e regras programáticas formam um conjunto ordenado de regras. Se regras igualmente específicas entrarem em conflito, a regra adicionada por último vencerá. A ordem das chamadas no callback AddTracing, portanto, importa quando AddConfiguration, EnableTracing e DisableTracing adicionam regras igualmente específicas.

Comparar nomes de fonte da atividade

Nomes de origem, nomes de operação e nomes de listener usam comparação ordinal que não diferencia maiúsculas de minúsculas. As regras de nome de origem dão suporte a estas formas de correspondência:

  • Um nome de fonte vazio corresponde a todas as fontes.
  • Um nome de origem sem um curinga corresponde por prefixo. Por exemplo, Contoso corresponde a Contoso.Orders e ContosoPayments; o comparador não exige um separador após o prefixo.
  • Um nome de origem com um * curinga corresponde a um prefixo e sufixo. Por exemplo, Contoso.*.Storage corresponde a Contoso.Orders.Storage, mas não Contoso.Orders.Api.
  • Um nome de origem de * corresponde a todas as origens.

Os nomes das operações correspondem exatamente. Eles não usam correspondência de prefixo ou curinga.

Aplicar precedência da regra

Para cada ouvinte, origem, operação e combinação de escopo, a infraestrutura de rastreamento escolhe uma regra correspondente. Ele compara as regras correspondentes nesta ordem:

  • Uma regra específica do ouvinte tem precedência sobre uma regra para todos os ouvintes.
  • Uma regra de origem tem precedência sobre uma regra padrão. Se duas expressões de origem corresponderem, a expressão mais longa terá precedência. A comparação usa o comprimento da expressão, incluindo um * curinga.
  • Uma regra de operação tem precedência sobre uma regra de nível de origem.
  • Uma regra somente global ou somente local tem precedência sobre uma regra que abrange ambos os escopos.
  • A última regra tem precedência quando todos os fatores anteriores são iguais.

A comparação é interrompida na primeira diferença. Por exemplo, uma regra padrão específica do listener tem precedência sobre uma regra específica da source que se aplica a todos os listeners porque a especificidade do listener é avaliada primeiro.

As regras de operação também controlam as assinaturas de origem. Um ouvinte se inscreve em uma origem desabilitada por padrão quando uma regra de operação habilita pelo menos uma operação dessa origem. Em seguida, o ouvinte retorna None e ignora seus callbacks para operações desabilitadas.

Escolher fontes de atividades globais ou locais

A infraestrutura de rastreamento distingue dois escopos de origem de atividade:

  • Uma origem global é uma ActivitySource criada por meio do construtor. EnabledGlobalTracing as regras se aplicam a essas origens.
  • Uma origem local é ActivitySource criada pelo ActivitySourceFactory resolvido por injeção de dependência. EnabledLocalTracing as regras se aplicam a origens criadas por esse alocador.

Use Create quando quiser que o contêiner da injeção de dependência gerencie a origem e os ouvintes de rastreamento. Os ouvintes de um alocador ignoram as origens locais criadas por um alocador diferente. As regras em EnabledTracing se aplicam a ambos os tipos de origem.

Esses escopos só restringem os ouvintes registrados por AddTracing. Um ActivityListener independente usa os próprios ShouldListenTo e retornos de chamada de amostragem, mesmo para uma origem de atividade criada por ActivitySourceFactory.

Recarregar a configuração de rastreamento

AddConfiguration se inscreve no token de alteração pela configuração fornecida. Quando um provedor de configuração dá suporte ao recarregamento e relata uma alteração, a infraestrutura de rastreamento:

  • Recria o conjunto de regras.
  • Atualiza as assinaturas de origem de cada ouvinte registrado.
  • Aplica as regras atualizadas às atividades subsequentes.

O aplicativo pode continuar usando as mesmas ActivitySource instâncias após um recarregamento. As atividades subsequentes usam as regras atualizadas.

Para um provedor mutável que não relata alterações automaticamente, atualize a configuração e chame Reload. O exemplo completo usa essa abordagem com o provedor de configuração na memória.

Tratar configuração inválida

A configuração de rastreamento interpreta valores com TryParse. Ele aceita true e false sem diferenciar maiúsculas de minúsculas e permite espaço em branco ao redor. Ele não aceita 1, 0, yes ou on.

O carregador de configuração ignora silenciosamente um valor folha que não é um booleano válido. Ele também ignora seções desconhecidas ou malformadas que não correspondam ao esquema compatível. Verifique os nomes de chave cuidadosamente porque esses casos não produzem uma exceção.

Uma expressão de origem pode conter no máximo um * curinga. Uma regra com mais de um curinga lança um ArgumentException quando a regra é materializada, durante a inicialização do aplicativo ou após o recarregamento da configuração. Para regras programáticas, None também causa um ArgumentOutOfRangeException.

Execute o exemplo

O aplicativo de console .NET 11 a seguir cria uma operação habilitada e uma operação desabilitada. Em seguida, atualiza a regra da operação desabilitada, chama Reloade inicia a operação novamente por meio do mesmo 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

Os exemplos de C# e Visual Basic produzem o mesmo resultado:

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

Consulte também