Abilitare la traccia distribuita OpenTelemetry con il pianificatore di attività durevole

Il tracciamento distribuito offre visibilità end-to-end nell'esecuzione di orchestrazioni. Quando si abilita OpenTelemetry con Durable Task Scheduler, ogni orchestrazione, attività e sotto orchestrazione genera intervalli collegati che mostrano intervalli di tempo, ordinamento ed errori nell'intero flusso di lavoro. È possibile esportare queste tracce in qualsiasi back-end compatibile con OpenTelemetry, ad esempio Monitoraggio di Azure Application InsightsJaeger o Zipkin.

Durable Functions e gli SDK Durable Task SDKs supportano entrambi il tracciamento distribuito OpenTelemetry quando si utilizza il Durable Task Scheduler come back-end.

Come funziona

Gli SDK Durable Task strumentano automaticamente le orchestrazioni e le attività con intervalli OpenTelemetry. Il componente SDK crea un intervallo padre per ogni orchestrazione e intervalli figlio per ogni chiamata di attività, orchestrazione secondaria e timer. Il contesto di traccia si propaga automaticamente in tutte queste operazioni, quindi si ottiene una singola traccia correlata per l'intero flusso di lavoro.

L'albero di traccia risultante è simile al seguente:

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

Non è necessario aggiungere strumentazione personalizzata al codice dell'agente di orchestrazione o dell'attività. Registrare l'origine dell'attività con la configurazione Microsoft.DurableTask di OpenTelemetry e lasciare che sia l'SDK a gestire il resto.

Prerequisiti

  • Un progetto Funzioni di Azure con l'estensione Durable Functions versione 2.13.0 o successiva.
  • Pianificatore di attività durevole configurato come back-end di archiviazione per l'app per le funzioni.
  • Back-end compatibile con OpenTelemetry per la visualizzazione delle tracce (Application Insights, Jaeger o un altro agente di raccolta OTLP).
  • .NET 8 SDK o versione successiva.
  • I pacchetti NuGet Microsoft.DurableTask.Worker.AzureManaged e Microsoft.DurableTask.Client.AzureManaged.
  • I pacchetti NuGet OpenTelemetry, OpenTelemetry.Extensions.Hosting e OpenTelemetry.Exporter.OpenTelemetryProtocol.
  • Back-end compatibile con OpenTelemetry per la visualizzazione di tracce, ad esempio Application Insights per la produzione o Jaeger per lo sviluppo locale.

Abilitare la traccia distribuita

Per abilitare la traccia distribuita in Durable Functions, aggiornare il host.json e configurare un back-end di telemetria compatibile con OpenTelemetry.

Aggiornare il file host.json

Aggiungere la sezione tracing sotto durableTask nel file host.json:

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

Configurare Application Insights

Impostare la APPLICATIONINSIGHTS_CONNECTION_STRING variabile di ambiente nell'app per le funzioni.

Per lo sviluppo locale, aggiungerlo a local.settings.json:

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

Per le app ospitate Azure, aggiungerla come impostazione dell'applicazione in Configuration nel portale di Azure.

Annotazioni

Se in precedenza è stato usato APPINSIGHTS_INSTRUMENTATIONKEY, passare a APPLICATIONINSIGHTS_CONNECTION_STRING per le funzionalità più recenti.

Ridurre il rumore dei dati di telemetria

Per impedire ad Application Insights di eseguire il campionamento dei dati di traccia, escludere Request dalle regole di campionamento in host.json:

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

Registrare la sorgente di attività Microsoft.DurableTask con la configurazione di OpenTelemetry. Il Durable Task SDK crea automaticamente intervalli per orchestrazioni e attività quando registri questa sorgente.

Nel file Program.cs del processo di lavoro, aggiungere la traccia OpenTelemetry con l'origine dell'attività Durable Task:

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();

La riga chiave è .AddSource("Microsoft.DurableTask"), che indica a OpenTelemetry di acquisire gli intervalli generati da Durable Task SDK.

Configurare l'endpoint OTLP

I frammenti di codice precedenti fanno riferimento alla OTEL_EXPORTER_OTLP_ENDPOINT variabile di ambiente per impostare la destinazione per i dati di traccia. Impostare questa variabile in base al back-end:

Back-end Valore endpoint Protocollo
Jaeger (locale) http://localhost:4317 gRPC
Jaeger (locale, HTTP) http://localhost:4318 HTTP/protobuf
Collettore OpenTelemetry http://<collector-host>:4317 gRPC
Monitoraggio di Azure (tramite OTLP) Utilizzare invece l'esportatore Monitoraggio di Azure N/A

Per lo sviluppo locale con Jaeger, l'impostazione predefinita http://localhost:4317 funziona quando Jaeger è in esecuzione con OTLP gRPC abilitato (porta 4317). JavaScript SDK usa HTTP/protobuf per impostazione predefinita, quindi ha come destinazione la porta 4318 con il percorso /v1/traces.

Visualizzare le tracce in locale con l'interfaccia utente di Jaeger

Per lo sviluppo locale, usare Durable Task Scheduler emulator con Jaeger per visualizzare le tracce. Usare un docker-compose.yml per avviare entrambi i servizi:

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

Avviare l'infrastruttura:

docker compose up -d

Dopo aver eseguito l'applicazione, aprire l'interfaccia utente jaeger all'indirizzo http://localhost:16686 e cercare il nome del servizio (ad esempio, durable-worker) per visualizzare le tracce.

Per lo sviluppo locale con Durable Functions, i dati di traccia distribuiti vengono inviati ad Application Insights per impostazione predefinita. Per visualizzare le tracce in locale senza eseguire la distribuzione, è possibile aggiungere un esportatore OTLP insieme ad Application Insights in Program.cs dell'app per le funzioni.

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

Eseguire quindi Jaeger in locale con docker run -d -p 16686:16686 -p 4317:4317 jaegertracing/jaeger:latest e aprire l'interfaccia utente jaeger all'indirizzo http://localhost:16686.

Visualizzare le tracce in Application Insights

Per i carichi di lavoro di produzione, Application Insights è il back-end di telemetria consigliato.

Quando DistributedTracingEnabled è impostato su true con Version impostato su V2 in host.json, l'app Durable Functions genera intervalli correlati ad Application Insights. Per visualizzare la traccia di orchestrazione completa nel portale di Azure:

  1. Passare alla risorsa di Application Insights nel portale di Azure.
  2. Aprire la ricerca di transazioni e cercare l'orchestrazione in base al nome o all'ID istanza.
  3. Selezionare una traccia per visualizzare la transazione completa con tutti i segmenti correlati.

La traccia mostra l'orchestrazione come intervallo padre con intervalli figlio per ogni chiamata di attività, orchestrazione secondaria e attesa timer. I modelli seguenti producono forme di traccia distinte:

Modello Forma di traccia
Concatenamento di funzioni Intervalli di attività sequenziali annidati sotto l'intervallo dell'agente di orchestrazione.
Fan-out/fan-in Le attività parallele si sovrappongono nel tempo.
Interazione umana Intervallo dell'agente di orchestrazione con una lunga attesa per un evento esterno.
Monitor L'attività ripetuta si estende con attese del timer tra le iterazioni.

Configurare l'utilità di esportazione OTLP per inviare tracce ad Application Insights usando l'utilità di esportazione Monitoraggio di Azure OpenTelemetry oppure esportarla tramite OTLP a un agente di raccolta OpenTelemetry che inoltra ad Application Insights.

Installare il pacchetto NuGet Azure.Monitor.OpenTelemetry.Exporter e sostituire l'OTLP exporter con:

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

Quali dati di traccia vengono visualizzati

I dati di traccia prodotti dagli SDK di Durable Task includono:

Tipo di intervallo Descrizione
create_orchestration Intervallo lato client generato durante la pianificazione di una nuova orchestrazione
orchestration Intervallo di orchestrazione lato server che copre il ciclo di vita di esecuzione completo
activity:<name> Intervallo per ogni chiamata di attività, che mostra la tempistica e il risultato
sub_orchestration:<name> Intervallo per ogni chiamata di orchestrazione secondaria
timer Intervallo di attese timer durevoli

Ogni intervallo include attributi come durabletask.type, durabletask.task.namedurabletask.task.instance_id, e durabletask.task.task_id. Le attività e le orchestrazioni con esito negativo includono i dettagli degli errori nello stato e negli eventi dell'intervallo.

Risoluzione dei problemi

Issue Resolution
Non vengono visualizzate tracce Verificare che l'origine dell'attività Microsoft.DurableTask sia registrata e che l'endpoint di esportazione sia raggiungibile.
Le tracce sono incomplete Verificare che OpenTelemetry SDK sia inizializzato prima di Durable Task SDK (in particolare in JavaScript/TypeScript).
Intervalli mancanti in Application Insights Disabilitare o modificare le impostazioni di campionamento per impedire l'eliminazione dei dati di traccia.
Le tracce non si correlano Verificare di usare Durable Task Scheduler come infrastruttura di supporto. La propagazione del contesto di traccia richiede lo scheduler.

Esempio di codice