Conceitos de rastreamento distribuí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árias máquinas ou processos. Consulte o Distributed Tracing Overview para obter informações gerais sobre onde o rastreamento distribuído é útil.
Rastros e Atividades
Cada vez que uma nova solicitação é recebida por um aplicativo, ela pode ser associada a um rastreamento. Em componentes de aplicativo escritos em .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 muitos processos distintos. A primeira atividade criada para uma nova solicitação forma a raiz da árvore de rastreamento e rastreia a duração total e o tratamento bem-sucedido/falhado da solicitação. As atividades infantis podem ser criadas opcionalmente para subdividir o trabalho em diferentes etapas que podem ser acompanhadas individualmente. Por exemplo, dada uma Atividade que rastreou uma solicitação HTTP de entrada específica em um servidor Web, atividades filhas podem ser criadas para rastrear cada uma das consultas de banco de dados necessárias para concluir a solicitação. Isso permite que a duração e o sucesso de cada consulta sejam registrados de forma independente. As atividades podem registar outras informações para cada unidade de trabalho, como OperationName, pares nome-valor chamados Tagse Events. O nome identifica o tipo de trabalho que está sendo executado, as tags podem registrar parâmetros descritivos do trabalho e os eventos são um mecanismo de registro simples para registrar mensagens de diagnóstico com carimbo de data/hora.
Observação
Outro nome comum da indústria para unidades de trabalho em um traço distribuído são 'Spans'. O .NET adotou o termo "Atividade" há muitos anos, antes que o nome "Span" estivesse bem estabelecido para este 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 da NET suporta dois esquemas de ID: o padrão W3C TraceContext, que é o padrão no .NET 5+, e uma convenção .NET mais antiga chamada 'Hierarchical' que está disponível para compatibilidade com versões anteriores. Activity.DefaultIdFormat controla qual esquema de identificação é usado. No padrão TraceContext do W3C, a cada rastreamento é atribuído um trace-id de 16 bytes globalmente exclusivo (Activity.TraceId), e a cada atividade dentro do rastreamento é atribuído um span-id exclusivo de 8 bytes (Activity.SpanId). Cada atividade regista o trace-id, o seu próprio span-id e o span-id do seu pai (Activity.ParentSpanId). Como os rastreamentos distribuídos podem rastrear o trabalho através dos limites do processo, as Atividades pai e filho podem não estar no mesmo processo. A combinação de um identificador de rastreamento e um identificador de intervalo pai pode identificar exclusivamente a atividade principal globalmente, independentemente do processo em que ela 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. Definir Activity.ForceDefaultIdFormat como true substitui esse comportamento e cria todas as novas Atividades com o 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 nesse thread, acessível via Activity.Current. A atividade atual flui automaticamente através de todas as chamadas síncronas numa linha de execução, seguindo chamadas assíncronas que são processadas em diferentes linhas de execução. 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 sua empresa-mãe. 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 o Activity.StartTimeUtc. Quando para, Activity.Duration é calculado como a diferença entre a hora atual e a hora de início.
Coordene através dos limites de processos
Para acompanhar o trabalho através dos limites do processo, os IDs pai de atividade precisam ser transmitidos pela rede para que o processo de recebimento possa criar Atividades que se referem a eles. Ao usar o formato de ID do W3C TraceContext, o .NET também utiliza os cabeçalhos HTTP recomendados pelo padrão para transmitir essas informações. Ao usar o formato de ID de Hierarchical, o .NET usa um cabeçalho HTTP de ID de solicitação personalizado para transmitir a ID. Ao contrário de muitos outros tempos de execução de linguagem, as bibliotecas de caixa de entrada 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 tempo de execução também entende como propagar o identificador por meio de chamadas síncronas e assíncronas. Isso significa que os 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 bibliotecas de terceiros. Bibliotecas de terceiros podem adicionar suporte para transmitir IDs em protocolos de mensagem não-HTTP ou suportar convenções de codificação personalizadas para HTTP.
Recolha de vestígios
O código instrumentado pode criar objetos Activity como parte de um rastreamento distribuído, mas as informações nesses objetos precisam ser transmitidas e serializadas em um armazenamento persistente centralizado para que todo o rastreamento possa ser revisado posteriormente de forma útil. Há várias bibliotecas de coleção de telemetria que podem fazer essa tarefa, como Application Insights, OpenTelemetryou 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. O ActivityListener suporta a observação de qualquer atividade, independentemente de o desenvolvedor ter algum conhecimento prévio sobre ela. Isso torna o ActivityListener uma solução de uso geral simples e flexível. Por outro lado, o uso de DiagnosticListener é um cenário mais complexo que requer que o código instrumentado aceite invocando DiagnosticSource.StartActivity e a biblioteca de coleções precisa saber as informações de nomenclatura exatas que o código instrumentado usou ao iniciá-lo. O uso de DiagnosticSource e DiagnosticListener permite que o criador e o ouvinte troquem objetos .NET arbitrários e estabeleçam convenções de passagem de informações personalizadas.
Amostragem
Para melhorar o desempenho em aplicativos de alta taxa de transferência, o rastreamento distribuído no .NET oferece 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 coleta de telemetria podem controlar a amostragem com a função de retorno ActivityListener.Sample. A biblioteca de log pode optar por não criar a atividade de logging, criá-la com o mínimo de informações necessárias para propagar IDs de rastreamento distribuídos ou preenchê-la com informações de diagnóstico completas. Essas escolhas compensam o aumento da sobrecarga de desempenho para aumentar a utilidade do diagnóstico. As atividades que são iniciadas usando o padrão mais antigo de invocar Activity.Activity e DiagnosticSource.StartActivity também podem oferecer suporte à amostragem do DiagnosticListener chamando DiagnosticSource.IsEnabledpela primeira vez. 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, preenchida e transmitida em cerca de um microssegundo no hardware moderno. A amostragem pode reduzir o custo da instrumentação para menos de 100 nanossegundos para cada atividade que não é registrada.
Próximos passos
Para obter um código de exemplo para começar a usar o rastreamento distribuído em aplicativos .NET, consulte o Distributed Tracing Instrumentation.
Para obter uma lista de atividades emitidas nativamente pelo .NET, consulte Atividades integradas no .NET.