Conceitos de rastreamento distribuído do .NET
O rastreamento distribuído é uma técnica de diagnóstico que ajuda os engenheiros a localizar falhas e problemas de desempenho em aplicativos, especialmente aqueles que podem ser distribuídos em vários computadores ou processos. Consulte a Visão geral do Rastreamento Distribuído para obter informações gerais sobre onde o rastreamento distribuído é útil.
Rastreamentos e atividades
Sempre que uma nova solicitação é recebida por um aplicativo, ela pode ser associada a um rastreamento. Nos componentes de aplicativo escritos no .NET, as unidades de trabalho em um rastreamento são representadas por instâncias de System.Diagnostics.Activity e o rastreamento como um todo forma uma árvore dessas Atividades, potencialmente abrangendo vários processos distintos. A primeira atividade criada para uma nova solicitação forma a raiz da árvore de rastreamento e controla a duração geral e o êxito/falha ao lidar com a solicitação. As atividades filho podem ser criadas opcionalmente para subdividir o trabalho em diferentes etapas que podem ser rastreadas individualmente. Por exemplo, considerando uma atividade que rastreou uma solicitação HTTP de entrada específica em um servidor web, atividades filhas podem ser criadas para acompanhar cada uma das consultas de banco de dados necessárias para concluir a solicitação. Isso permite que a duração e o êxito de cada consulta sejam registrados independentemente. As atividades podem registrar outras informações para cada unidade de trabalho, como OperationName, pares nome-valor chamados Tags e Events. O nome identifica o tipo de trabalho que está sendo executado, as marcas podem registrar parâmetros descritivos do trabalho e os eventos são um mecanismo de log simples para registrar mensagens de diagnóstico com carimbo de data/hora.
Nota
Outro nome comum do setor para unidades de trabalho em um rastreamento distribuído são 'Spans'. O .NET adotou o termo 'Atividade' há muitos anos, antes do nome 'Span' ser bem estabelecido para esse conceito.
IDs de atividade
Parent-Child relações entre atividades na árvore de rastreamento distribuída são estabelecidas usando IDs exclusivas. . A implementação do rastreamento distribuído pelo NET dá suporte a dois esquemas de ID: o padrão W3C TraceContext, que é o padrão no .NET 5+, e uma convenção do .NET mais antiga chamada "Hierárquica" disponível para compatibilidade com versões anteriores. Activity.DefaultIdFormat controla qual esquema de ID é usado. No padrão TraceContext W3C, cada rastreamento recebe uma ID de rastreamento de 16 bytes globalmente exclusiva (Activity.TraceId) e cada atividade dentro do rastreamento recebe uma ID de intervalo de 8 bytes exclusiva (Activity.SpanId). Cada Atividade registra a ID de rastreamento, sua própria ID de intervalo e a ID de intervalo de seu pai (Activity.ParentSpanId). Como os rastreamentos distribuídos podem rastrear o trabalho entre os limites do processo, as Atividades pai e filho podem não estar no mesmo processo. A combinação de uma ID de rastreamento e id de intervalo pai pode identificar exclusivamente a Atividade pai globalmente, independentemente do processo em que reside.
Activity.DefaultIdFormat controla qual formato de ID é usado para iniciar novos rastreamentos, mas, por padrão, adicionar uma nova atividade a um rastreamento existente usa qualquer formato que a Atividade pai esteja usando. A definição de Activity.ForceDefaultIdFormat como true substitui esse comportamento e cria todas as novas Atividades com DefaultIdFormat, mesmo quando o pai usa um formato de ID diferente.
Iniciar e parar atividades
Cada thread em um processo pode ter um objeto Activity correspondente que rastreia o trabalho que ocorre naquele thread, acessível via Activity.Current. A atividade atual flui automaticamente ao longo de todas as chamadas síncronas em um thread e segue chamadas assíncronas que são processadas em diferentes threads. Se a Atividade A for a atividade atual em um thread e o código iniciar uma nova Atividade B, B se tornará a nova atividade atual nesse thread. Por padrão, a atividade B também tratará a Atividade A como seu pai. Quando a Atividade B for interrompida posteriormente, a atividade A será restaurada como a atividade atual no thread. Quando uma Atividade é iniciada, ela captura a hora atual como Activity.StartTimeUtc. Quando isto para, Activity.Duration é calculado como a diferença entre o tempo atual e o tempo de início.
Coordenar através dos limites dos processos
Para rastrear o trabalho entre os limites do processo, as IDs pai da Atividade precisam ser transmitidas pela rede para que o processo de recebimento possa criar Atividades que façam referência a elas. Ao usar o formato W3C TraceContext ID, o .NET também usa os cabeçalhos HTTP recomendados pelo padrão para transmitir essas informações. Ao usar o formato de ID Hierarchical, o .NET usa um cabeçalho HTTP de id de solicitação personalizado para transmitir a ID. Ao contrário de muitos outros runtimes de linguagem, as bibliotecas internas do .NET, como o servidor Web ASP.NET e o System.Net.Http, entendem nativamente como decodificar e codificar IDs de atividade em mensagens HTTP. O runtime também entende como transferir o identificador por meio de chamadas síncronas e assíncronas. Isso significa que aplicativos .NET que recebem e emitem mensagens HTTP participam do fluxo de IDs de rastreamento distribuído automaticamente, sem codificação especial pelo desenvolvedor do aplicativo ou dependências de biblioteca de terceiros. Bibliotecas de terceiros podem adicionar suporte para transmitir IDs por protocolos de mensagem não HTTP ou dar suporte a convenções de codificação personalizadas para HTTP.
Coletar rastreamentos
O código instrumentado pode criar objetos Activity como parte de um traço distribuído, mas as informações nesses objetos precisam ser transmitidas e serializadas em um armazenamento persistente centralizado para que todo o traço possa ser analisado posteriormente. Há várias bibliotecas de coleções de telemetria que podem fazer essa tarefa, como application insights, OpenTelemetry ou uma biblioteca fornecida por um fornecedor de telemetria ou APM de terceiros. Como alternativa, os desenvolvedores podem criar sua própria coleção de telemetria de atividade personalizada usando System.Diagnostics.ActivityListener ou System.Diagnostics.DiagnosticListener. ActivityListener dá suporte à observação de qualquer atividade, independentemente de o desenvolvedor ter algum conhecimento prévio sobre ela. Isso torna ActivityListener uma solução de finalidade geral simples e flexível. Por outro lado, usar o `DiagnosticListener` é um cenário mais complexo que exige que o código instrumentado opte por invocar DiagnosticSource.StartActivity e a biblioteca de coleções precisa saber exatamente as informações de nomenclatura que o código instrumentado usou ao iniciá-lo. O uso de DiagnosticSource e DiagnosticListener permite que o criador e o ouvinte troquem objetos arbitrários do .NET e estabeleçam convenções personalizadas de passagem de informações.
amostragem
Para melhorar o desempenho em aplicativos de alta taxa de transferência, o rastreamento distribuído no .NET dá suporte à amostragem apenas de um subconjunto de rastreamentos em vez de gravar todos eles. Para atividades criadas com a API ActivitySource.StartActivity recomendada, as bibliotecas de coleção de telemetria podem controlar a amostragem com o retorno de chamada ActivityListener.Sample. A biblioteca de logs pode optar por não criar a Atividade, criá-la com informações mínimas necessárias para propagar a distribuição de IDs de rastreamento ou para preenchê-la com informações de diagnóstico completas. Essas escolhas equilibram o aumento da sobrecarga de desempenho com o aumento da utilidade de diagnóstico. As Atividades que são iniciadas usando o padrão mais antigo de invocação Activity.Activity e DiagnosticSource.StartActivity também podem dar suporte à amostragem DiagnosticListener chamando DiagnosticSource.IsEnabled primeiro. Mesmo ao capturar informações completas de diagnóstico, a implementação do .NET foi projetada para ser rápida , juntamente com um coletor eficiente, uma atividade pode ser criada, populada e transmitida em cerca de um microssegundo no hardware moderno. A amostragem pode reduzir o custo de instrumentação para menos de 100 nanossegundos para cada Atividade não registrada.
Próximas etapas
Para obter um código de exemplo para começar a usar o rastreamento distribuído em aplicativos .NET, consulte a Instrumentação de Rastreamento Distribuído .
Para obter uma lista de atividades emitidas nativamente pelo .NET, consulte Atividades internas no .NET.