Habilitar o rastreamento distribuído do OpenTelemetry com o Agendador de Tarefa Durável

O rastreamento distribuído fornece visibilidade de ponta a ponta sobre a execução da orquestração. Quando você habilita o OpenTelemetry com o Agendador de Tarefas Duráveis, cada orquestração, atividade e sub-orquestração gera intervalos vinculados que mostram tempo, ordenação e erros no fluxo de trabalho inteiro. Você pode exportar esses rastreamentos para qualquer back-end compatível com OpenTelemetry, como Azure Monitor Application Insights, Jaeger ou Zipkin.

Durable Functions e os SDKs de Tarefas Duráveis autônomos dão suporte ao rastreamento distribuído OpenTelemetry ao usar o Agendador de Tarefas Duráveis como o back-end.

Como funciona

Os SDKs de Tarefas Duráveis instrumentam de forma automática orquestrações e atividades com intervalos OpenTelemetry. O SDK cria um intervalo pai para cada orquestração e intervalos filho para cada chamada de atividade, sub-orquestração e temporizador. O contexto de rastreamento se propaga automaticamente em todas essas operações, para que você obtenha um único rastreamento correlacionado para todo o fluxo de trabalho.

A árvore de rastreamento resultante se parece com:

create_orchestration (client)
  └─ orchestration (server)
       ├─ activity:Step1
       ├─ activity:Step2
       └─ activity:Step3

Você não precisa adicionar instrumentação personalizada ao seu orquestrador ou código de atividade. Registre a fonte de atividade Microsoft.DurableTask com sua configuração openTelemetry e o SDK manipula o restante.

Pré-requisitos

  • Um projeto Azure Functions com a extensão Durable Functions versão 2.13.0 ou posterior.
  • Agendador de Tarefas Duráveis configurado como o back-end de armazenamento para o aplicativo de funções.
  • Um back-end compatível com OpenTelemetry para exibir rastreamentos (Application Insights, Jaeger ou outro coletor OTLP).
  • .NET 8 SDK ou posterior.
  • Os pacotes NuGet Microsoft.DurableTask.Worker.AzureManaged e Microsoft.DurableTask.Client.AzureManaged.
  • Os pacotes OpenTelemetry, OpenTelemetry.Extensions.Hosting e OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet.
  • Um back-end compatível com OpenTelemetry para exibir rastreamentos, como o Application Insights para produção ou o Jaeger para desenvolvimento local.

Habilitar o rastreamento distribuído

Para habilitar o rastreamento distribuído em Durable Functions, atualize o host.json e configure um back-end de telemetria compatível com OpenTelemetry.

Atualizar host.json

Adicione a seção tracing em durableTask no seu arquivo host.json :

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "tracing": {
        "DistributedTracingEnabled": true,
        "Version": "V2"
      }
    }
  }
}

Configurar o Application Insights

Defina a variável de APPLICATIONINSIGHTS_CONNECTION_STRING ambiente em seu aplicativo de funções.

Para desenvolvimento local, adicione-o a local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "<your-connection-string>"
  }
}

Para aplicativos hospedados Azure, adicione-o como uma configuração de aplicativo em Configuration no portal Azure.

Observação

Se você usou APPINSIGHTS_INSTRUMENTATIONKEY anteriormente, alterne para APPLICATIONINSIGHTS_CONNECTION_STRING para obter as funcionalidades mais recentes.

Reduzir o ruído de telemetria

Para impedir que o Application Insights apresente uma amostragem de dados de rastreamento, exclua Request das regras de amostragem no host.json:

{
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  }
}

Registre a fonte de atividade Microsoft.DurableTask com sua configuração OpenTelemetry. O SDK de Tarefas Duráveis cria de forma automática intervalos para orquestrações e atividades quando você registra essa origem.

No Program.cs do trabalho, adicione o rastreamento OpenTelemetry com a fonte de atividade de Tarefa Durável:

using Microsoft.DurableTask;
using Microsoft.DurableTask.Worker;
using Microsoft.DurableTask.Worker.AzureManaged;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = Host.CreateApplicationBuilder(args);

// Configure OpenTelemetry tracing
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri(
                    Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")
                    ?? "http://localhost:4317");
            });
    });

// Build connection string from environment variables
string endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? "http://localhost:8080";
string taskHub = Environment.GetEnvironmentVariable("TASKHUB") ?? "default";
string connectionString = endpoint.Contains("localhost")
    ? $"Endpoint={endpoint};TaskHub={taskHub};Authentication=None"
    : $"Endpoint={endpoint};TaskHub={taskHub};Authentication=DefaultAzure";

// Configure Durable Task worker
builder.Services.AddDurableTaskWorker()
    .AddTasks(tasks =>
    {
        tasks.AddOrchestratorFunc<string, string>(
            "OrderProcessingOrchestration", async (ctx, input) =>
        {
            var validated = await ctx.CallActivityAsync<string>("ValidateOrder", input);
            var payment = await ctx.CallActivityAsync<string>("ProcessPayment", validated);
            var shipment = await ctx.CallActivityAsync<string>("ShipOrder", payment);
            var result = await ctx.CallActivityAsync<string>("SendNotification", shipment);
            return result;
        });

        tasks.AddActivityFunc<string, string>("ValidateOrder", (ctx, input) =>
            Task.FromResult($"Validated({input})"));
        tasks.AddActivityFunc<string, string>("ProcessPayment", (ctx, input) =>
            Task.FromResult($"Paid({input})"));
        tasks.AddActivityFunc<string, string>("ShipOrder", (ctx, input) =>
            Task.FromResult($"Shipped({input})"));
        tasks.AddActivityFunc<string, string>("SendNotification", (ctx, input) =>
            Task.FromResult($"Notified({input})"));
    })
    .UseDurableTaskScheduler(connectionString);

var host = builder.Build();
await host.RunAsync();

A linha de chave é .AddSource("Microsoft.DurableTask"), que indica ao OpenTelemetry que capture intervalos emitidos pelo SDK de Tarefa Durável.

Configurar o ponto de extremidade OTLP

Os snippets de código acima fazem referência à OTEL_EXPORTER_OTLP_ENDPOINT variável de ambiente para definir o destino dos dados de rastreamento. Defina essa variável com base no back-end:

Backend Valor do ponto de extremidade Protocolo
Jaeger (local) http://localhost:4317 gRPC
Jaeger (local, HTTP) http://localhost:4318 HTTP/protobuf
Coletor OpenTelemetry http://<collector-host>:4317 gRPC
Azure Monitor (via OTLP) Em vez disso, use o exportador de Azure Monitor N/A

Para desenvolvimento local com Jaeger, o padrão http://localhost:4317 funciona quando Jaeger está em execução com OTLP gRPC habilitado (porta 4317). O SDK do JavaScript usa HTTP/protobuf por padrão, portanto, ele acessa a porta 4318 com o caminho /v1/traces.

Exibir rastreamentos localmente com o Jaeger UI

Para desenvolvimento local, use o emulador do Agendador de Tarefas Duráveis com Jaeger para exibir rastreamentos. Use um docker-compose.yml para iniciar ambos os serviços:

services:
  dts-emulator:
    image: mcr.microsoft.com/dts/dts-emulator:latest
    ports:
      - "8080:8080"  # gRPC
      - "8082:8082"  # Dashboard
  jaeger:
    image: jaegertracing/jaeger:latest
    ports:
      - "16686:16686"  # Jaeger UI
      - "4317:4317"    # OTLP gRPC
      - "4318:4318"    # OTLP HTTP

Inicie a infraestrutura:

docker compose up -d

Depois de executar seu aplicativo, abra a interface do Jaeger em http://localhost:16686 e pesquise pelo nome de seu serviço (por exemplo, durable-worker) para visualizar os rastros.

Para o desenvolvimento local com Durable Functions, os dados de rastreamento distribuídos são enviados para o Application Insights por padrão. Para visualizar os traços localmente sem precisar fazer a implantação, você pode adicionar um exportador OTLP junto com o Application Insights no seu aplicativo de função Program.cs:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddOtlpExporter(opts =>
            {
                opts.Endpoint = new Uri("http://localhost:4317");
            });
    });

Em seguida, execute Jaeger localmente com docker run -d -p 16686:16686 -p 4317:4317 jaegertracing/jaeger:latest e abra a interface do usuário Jaeger em http://localhost:16686.

Exibir rastreamentos no Application Insights

Para cargas de trabalho de produção, o Application Insights é o back-end de telemetria recomendado.

Depois que DistributedTracingEnabled é definido como true com Version definido como V2 em host.json, seu aplicativo Durable Functions emite intervalos correlacionados para o Application Insights. Para exibir o rastreamento de orquestração completo no portal do Azure:

  1. Acesse o recurso do Application Insights no portal do Azure.
  2. Abra a Pesquisa de Transações e pesquise sua orquestração por nome ou ID da instância.
  3. Selecione um rastreamento para exibir a transação de ponta a ponta com todos os intervalos correlacionados.

O traço mostra a orquestração como um intervalo principal, com intervalos filhos para cada chamada de atividade, suborquestração e espera de temporizador. Os seguintes padrões produzem formas de rastreamento distintas:

Padrão Forma de rastreamento
Encadeamento de funções As atividades sequenciais se estendem aninhadas sob o intervalo do orquestrador.
Fan-out/fan-in Atividades paralelas ocorrem simultaneamente e se sobrepõem no tempo.
Interação humana Um intervalo de orquestrador com uma espera longa por um evento externo.
Monitor Intervalos de atividades repetidas com esperas de temporizador entre as iterações.

Configure o exportador OTLP para enviar rastreamentos ao Application Insights usando o exportador Azure Monitor OpenTelemetry ou exporte por meio de OTLP para um Coletor OpenTelemetry que encaminhe para o Application Insights.

Instale o pacote NuGet Azure.Monitor.OpenTelemetry.Exporter e substitua o exportador OTLP por:

builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("durable-worker"))
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.DurableTask")
            .AddAzureMonitorTraceExporter(opts =>
            {
                opts.ConnectionString = Environment.GetEnvironmentVariable(
                    "APPLICATIONINSIGHTS_CONNECTION_STRING");
            });
    });

O que os dados de rastreamento mostram

Os dados de rastreamento produzidos pelos SDKs de Tarefa Durável incluem:

Tipo de intervalo Descrição
create_orchestration O intervalo do cliente emitido ao agendar uma nova orquestração
orchestration A abrangência da orquestração do servidor que abrange todo o ciclo de vida de execução
activity:<name> Um intervalo para cada invocação de atividade, mostrando o tempo e o resultado
sub_orchestration:<name> Um intervalo para cada chamada de sub-orquestração
timer Um intervalo para temporizadores duráveis aguarda

Cada intervalo inclui atributos como durabletask.type, durabletask.task.namee durabletask.task.instance_iddurabletask.task.task_id. Atividades e orquestrações com falha incluem detalhes de erro no status e em eventos do intervalo.

Solução de problemas

Questão Resolução
Nenhum vestígio aparece Verifique se a origem da atividade Microsoft.DurableTask está registrada e se o ponto de extremidade do exportador está acessível.
Os rastreamentos estão incompletos Verifique se o SDK do OpenTelemetry é inicializado antes do SDK de Tarefas Duráveis (especialmente em JavaScript/TypeScript).
Intervalos ausentes no Application Insights Desabilite ou ajuste as configurações de amostragem para impedir que os dados de rastreamento sejam descartados.
Rastros não se correlacionam Verifique se você está usando o Agendador de Tarefas Duráveis como o back-end. A propagação de contexto de rastreamento exige o agendador.

Código de exemplo