Activer le suivi distribué OpenTelemetry avec Durable Task Scheduler

Le suivi distribué offre une visibilité de bout en bout sur l’exécution de l’orchestration. Lorsque vous activez OpenTelemetry avec Durable Task Scheduler, chaque orchestration, activité et sous-orchestration produit des spans liées qui affichent la chronologie, l'ordre et les erreurs dans l'ensemble du flux de travail. Vous pouvez exporter ces traces vers n’importe quel serveur principal compatible OpenTelemetry, comme Azure Monitor Application Insights, Jaeger ou Zipkin.

Durable Functions et les SDK de tâches durables autonomes prennent tous deux en charge le suivi distribué OpenTelemetry lors de l’utilisation du planificateur de tâches durables comme back-end.

Fonctionnement

Les SDK Durable Task instrumentent automatiquement les orchestrations et les activités avec des étendues OpenTelemetry. Le Kit de développement logiciel (SDK) crée une étendue parent pour chaque orchestration et des étendues enfants pour chaque appel d’activité, sous-orchestration et minuteur. Le contexte de trace se propage automatiquement dans toutes ces opérations, de sorte que vous obtenez une trace unique et corrélée pour l’ensemble du flux de travail.

L’arborescence de trace résultante ressemble à ceci :

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

Vous n’avez pas besoin d’ajouter d’instrumentation personnalisée à votre orchestrateur ou à votre code d’activité. Inscrivez la source d’activité Microsoft.DurableTask avec votre configuration OpenTelemetry, et le SDK gère le reste.

Prerequisites

  • Projet Azure Functions avec l’extension Durable Functions version 2.13.0 ou ultérieure.
  • Planificateur de tâches durables configuré comme arrière-plan de stockage pour votre application fonctionnelle.
  • Un back-end compatible OpenTelemetry pour l’affichage des traces (Application Insights, Jaeger ou un autre collecteur OTLP).
  • SDK .NET 8 ou version ultérieure.
  • Packages NuGet Microsoft.DurableTask.Worker.AzureManaged et Microsoft.DurableTask.Client.AzureManaged.
  • Packages OpenTelemetry, OpenTelemetry.Extensions.Hosting et OpenTelemetry.Exporter.OpenTelemetryProtocol NuGet.
  • Un back-end compatible avec OpenTelemetry pour visualiser les traces, comme Application Insights pour la production ou Jaeger pour le développement local.

Activer le suivi distribué

Pour activer le suivi distribué dans Durable Functions, mettez à jour votre host.json et configurez un back-end de télémétrie compatible OpenTelemetry.

Mise à jour de host.json

Ajoutez la tracing section sous durableTask, dans votre fichier host.json :

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

Configurer Application Insights

Définissez la variable d’environnement APPLICATIONINSIGHTS_CONNECTION_STRING dans votre application de fonction.

Pour le développement local, ajoutez-le à local.settings.json:

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

Pour les applications hébergées Azure, ajoutez-la en tant que paramètre d’application sous Configuration dans le portail Azure.

Note

Si vous avez utilisé APPINSIGHTS_INSTRUMENTATIONKEY précédemment, basculez vers APPLICATIONINSIGHTS_CONNECTION_STRING pour bénéficier des fonctionnalités les plus récentes.

Réduire le bruit de télémétrie

Pour empêcher Application Insights d’extraire des données de trace, excluez Request les règles d’échantillonnage dans host.json:

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

Inscrivez la source d’activité Microsoft.DurableTask avec votre configuration OpenTelemetry. Le SDK Durable Task crée automatiquement des étendues pour les orchestrations et les activités lorsque vous inscrivez cette source.

Dans le fichier Program.cs de votre worker, ajoutez le suivi OpenTelemetry avec la source d’activité 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 ligne principale est .AddSource("Microsoft.DurableTask"), ce qui indique à OpenTelemetry de capturer des segments que le SDK Durable Task émet.

Configurer le point de terminaison OTLP

Les extraits de code ci-dessus référencent la OTEL_EXPORTER_OTLP_ENDPOINT variable d’environnement pour définir la destination des données de trace. Définissez cette variable en fonction de votre back-end :

Backend Valeur du point de terminaison Protocol
Jaeger (local) http://localhost:4317 gRPC
Jaeger (local, HTTP) http://localhost:4318 HTTP/protobuf
Collecteur OpenTelemetry http://<collector-host>:4317 gRPC
Azure Monitor (via OTLP) Utilisez plutôt l’exportateur Azure Monitor N/A

Pour le développement local avec Jaeger, la valeur par défaut http://localhost:4317 fonctionne quand Jaeger est en cours d’exécution avec otLP gRPC activé (port 4317). Le Kit de développement logiciel (SDK) JavaScript utilise http/protobuf par défaut. Il cible donc le port 4318 avec le chemin d’accès /v1/traces .

Afficher les traces localement avec l’interface utilisateur Jaeger

Pour le développement local, utilisez l’émulateur Durable Task Scheduler avec Jaeger pour afficher les traces. Utilisez un docker-compose.yml pour démarrer les deux services :

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

Démarrez l’infrastructure :

docker compose up -d

Après avoir exécuté votre application, ouvrez l’interface utilisateur Jaeger à l’adresse http://localhost:16686 et recherchez le nom de votre service (par exemple durable-worker) pour afficher les traces.

Pour le développement local avec Durable Functions, les données de suivi distribuées sont envoyées par défaut à Application Insights. Pour afficher les traces localement sans déployer, vous pouvez ajouter un exportateur OTLP avec Application Insights dans votre fonction de l'application Program.cs.

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

Ensuite, exécutez Jaeger localement avec docker run -d -p 16686:16686 -p 4317:4317 jaegertracing/jaeger:latest et ouvrez l’interface utilisateur Jaeger à l’adresse http://localhost:16686.

Afficher les traces dans Application Insights

Pour les charges de travail de production, Application Insights est le back-end de télémétrie recommandé.

Une fois DistributedTracingEnabled défini sur true avec Version défini sur V2 dans host.json, votre application Durable Functions émet des étendues corrélées à Application Insights. Pour afficher la trace d’orchestration complète dans le portail Azure :

  1. Accédez à votre ressource Application Insights dans le portail Azure.
  2. Ouvrez la recherche transactionnelle et recherchez votre orchestration par nom ou ID d’instance.
  3. Sélectionnez une trace pour afficher la transaction intégrale avec tous les segments corrélés.

La trace montre l’orchestration en tant qu’étendue parent, avec des étendues enfants pour chaque appel d’activité, sous-orchestration et attente de minuteur. Les modèles suivants produisent des formes de trace distinctes :

Modèle Forme de trace
Chaînage de fonctions Les étendues d’activités séquentielles sont imbriquées sous l’étendue de l’orchestrateur.
Fan-out/fan-in Les périodes d'activité parallèle se chevauchent dans le temps.
Interaction humaine Une étendue d’orchestrateur avec une longue attente pour un événement externe.
Monitor Des étendues d’activité répétées avec des attentes de minuteur entre les itérations.

Configurez l’exportateur OTLP pour envoyer des traces à Application Insights à l’aide de l’exportateur Azure Monitor OpenTelemetry ou exportez via OTLP vers un collecteur OpenTelemetry qui transfère à Application Insights.

Installez le package NuGet Azure.Monitor.OpenTelemetry.Exporter et remplacez l’exportateur OTLP par :

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

Quelles sont les données de trace qui s’affichent

Les données de trace produites par les kits SDK Durable Task incluent les éléments suivants :

Type d’étendue Description
create_orchestration L’étendue côté client émise lors de la planification d’une nouvelle orchestration
orchestration L’orchestration côté serveur couvre le cycle de vie d’exécution complet
activity:<name> Un tracé pour chaque appel d'une activité, affichant le timing et le résultat
sub_orchestration:<name> Un intervalle pour chaque appel de sous-orchestration
timer Une étendue pour les attentes de minuteur durable

Chaque étendue inclut des attributs tels que durabletask.type, , durabletask.task.namedurabletask.task.instance_id, et durabletask.task.task_id. Les activités et les orchestrations ayant échoué incluent les détails de l’erreur dans le statut de l’étendue et dans ses événements.

Résolution des problèmes

Problème Résolution
Aucune trace n’apparaît Vérifiez que la Microsoft.DurableTask source d’activité est inscrite et que le point de terminaison de l’exportateur est accessible.
Les traces sont incomplètes Vérifiez que le Kit de développement logiciel (SDK) OpenTelemetry est initialisé avant le Kit de développement logiciel (SDK) Durable Task (en particulier en JavaScript/TypeScript).
Étendues manquantes dans Application Insights Désactivez ou ajustez les paramètres d’échantillonnage pour empêcher la suppression des données de trace.
Les traces ne sont pas corrélées Vérifiez que vous utilisez Durable Task Scheduler comme back-end. La propagation du contexte de trace nécessite le planificateur.

Exemple de code