Partager via


Collecter une trace distribuée

Cet article s’applique à : ✔️ .NET Core 2.1 et versions ultérieures ✔️ .NET Framework 4.5 et versions ultérieures

Le code instrumenté peut créer des objets Activity dans le cadre d’une trace distribuée, mais les informations contenues dans ces objets doivent être collectées dans un stockage centralisé afin que la trace entière puisse être examinée ultérieurement. Dans ce tutoriel, vous allez collecter les données de télémétrie de trace distribuée de différentes façons afin qu’elles soient disponibles pour diagnostiquer les problèmes d’application si nécessaire. Consultez le tutoriel sur l’instrumentation si vous devez ajouter une nouvelle instrumentation.

Collecter des traces à l’aide d’OpenTelemetry

OpenTelemetry est un projet open source indépendant du fournisseur pris en charge par Cloud Native Computing Foundation qui vise à normaliser la génération et la collecte de données de télémétrie pour les logiciels natifs Cloud. Dans ces exemples, vous allez collecter et afficher des informations de trace distribuée sur la console. Pour savoir comment configurer OpenTelemetry pour envoyer des informations ailleurs, consultez le guide de prise en main d’OpenTelemetry.

Exemple ASP.NET

Prérequis

Créer un exemple d’application

Tout d’abord, créez une application web ASP.NET à utiliser comme application de démonstration.

dotnet new webapp

Cette application affiche une page web, mais aucune information de suivi distribuée n’est encore collectée si nous parcourons la page web.

Configurer la collecte

Pour utiliser OpenTelemetry, vous devez ajouter des références à plusieurs packages NuGet.

dotnet add package OpenTelemetry --version 1.4.0-rc1
dotnet add package OpenTelemetry.Exporter.Console --version 1.4.0-rc1
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.4.0-rc1
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --version 1.0.0-rc9.10

Notes

Au moment de l’écriture de cet article, la version 1.4.0 Release Candidate 1 était la dernière version d’OpenTelemetry disponible. Une fois qu’une version finale est disponible, utilisez-la à la place.

Ensuite, modifiez le code source dans Program.cs pour qu’il ressemble à ceci :

using OpenTelemetry;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddOpenTelemetry()
    .WithTracing(builder =>
    {
        builder.AddAspNetCoreInstrumentation();
        builder.AddConsoleExporter();
    }).StartWithHost();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Exécutez l’application et utilisez un navigateur web pour accéder à la page web hébergée. Maintenant que vous avez activé le suivi distribué OpenTelemetry, vous devez voir que des informations sur les requêtes web du navigateur sont imprimées dans la console :

Activity.TraceId:            9c4519ce65a667280daedb3808d376f0
Activity.SpanId:             727c6a8a6cff664f
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName:        /
Activity.Kind:               Server
Activity.StartTime:          2023-01-08T01:56:05.4529879Z
Activity.Duration:           00:00:00.1048255
Activity.Tags:
    net.host.name: localhost
    net.host.port: 5163
    http.method: GET
    http.scheme: http
    http.target: /
    http.url: http://localhost:5163/
    http.flavor: 1.1
    http.user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76
    http.status_code: 200
Resource associated with Activity:
    service.name: unknown_service:demo

Toutes les configurations OpenTelemetry se produisent dans les nouvelles lignes sources qui commencent par builder.Services.AddOpenTelemetry(). Vous avez utilisé .WithTracing(...) pour activer le suivi distribué. AddAspNetCoreInstrumentation() a activé OpenTelemetry pour collecter toutes les activités de trace distribuée produites par le serveur web ASP.NET Core et AddConsoleExporter() demande à OpenTelemetry d’envoyer ces informations à la console. Pour une application moins triviale, vous pouvez ajouter d’autres bibliothèques d’instrumentation pour collecter également le suivi pour les requêtes de base de données ou les requêtes HTTP sortantes. Vous pouvez également remplacer l’exportateur de console par un exportateur pour Jaeger, Zipken ou un autre service de supervision que vous avez choisi d’utiliser.

Exemple d’application console

Prérequis

Créer un exemple d’application

Avant que des données de télémétrie de trace distribuée ne puissent être collectées, vous devez les produire. Souvent, cette instrumentation se trouve dans des bibliothèques, mais par souci de simplicité, vous allez créer une petite application qui a un exemple d’instrumentation à l’aide de StartActivity. À ce stade, aucune collection n’a eu lieu, et StartActivity() n’a aucun effet secondaire et retourne une valeur null. Pour plus d’informations, consultez le tutoriel sur l’instrumentation.

dotnet new console

Les API de suivi distribuées nécessaires sont déjà incluses dans les applications qui ciblent .NET 5 et versions ultérieures. Pour les applications ciblant des versions antérieures de .NET, ajoutez le package NuGet System.Diagnostics.DiagnosticSource version 5 ou ultérieure.

dotnet add package System.Diagnostics.DiagnosticSource

Remplacez le contenu du fichier Program.cs généré par cet exemple de source :

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Sample.DistributedTracing
{
    class Program
    {
        static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

        static async Task Main(string[] args)
        {
            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

        static async Task DoSomeWork()
        {
            using (Activity a = s_source.StartActivity("SomeWork"))
            {
                await StepOne();
                await StepTwo();
            }
        }

        static async Task StepOne()
        {
            using (Activity a = s_source.StartActivity("StepOne"))
            {
                await Task.Delay(500);
            }
        }

        static async Task StepTwo()
        {
            using (Activity a = s_source.StartActivity("StepTwo"))
            {
                await Task.Delay(1000);
            }
        }
    }
}

L’exécution de l’application ne collecte pas encore de données de trace :

> dotnet run
Example work done

Configurer la collecte

Ajoutez le package NuGet OpenTelemetry.Exporter.Console.

dotnet add package OpenTelemetry.Exporter.Console

Mettez à jour Program.cs avec des directives OpenTelemetry using supplémentaires :

using OpenTelemetry;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

Mettez à jour Main() pour créer OpenTelemetry TracerProvider :

        public static async Task Main()
        {
            using var tracerProvider = Sdk.CreateTracerProviderBuilder()
                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                .AddSource("Sample.DistributedTracing")
                .AddConsoleExporter()
                .Build();

            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

À présent, l’application collecte des informations de trace distribuée et les affiche dans la console :

> dotnet run
Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-6081a9b8041cd840-01
Activity.ParentId:    00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: StepOne
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:46.8649754Z
Activity.Duration:    00:00:00.5069226
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-d2b283db91cf774c-01
Activity.ParentId:    00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: StepTwo
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:47.3838737Z
Activity.Duration:    00:00:01.0142278
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Activity.Id:          00-7759221f2c5599489d455b84fa0f90f4-9a52f72c08a9d447-01
Activity.DisplayName: SomeWork
Activity.Kind:        Internal
Activity.StartTime:   2021-03-18T10:46:46.8634510Z
Activity.Duration:    00:00:01.5402045
Resource associated with Activity:
    service.name: MySample
    service.instance.id: 909a4624-3b2e-40e4-a86b-4a2c8003219e

Example work done
Sources

Dans l’exemple de code, vous avez appelé AddSource("Sample.DistributedTracing") afin qu’OpenTelemetry capture les activités produites par ActivitySource qui étaient déjà présentes dans le code :

static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

Les données de télémétrie de n’importe quelle ActivitySource peuvent être capturées en appelant AddSource() avec le nom de la source.

Exportateurs

L’exportateur de console est utile pour les exemples rapides ou le développement local, mais dans un déploiement de production, vous souhaiterez probablement envoyer des traces à un magasin centralisé. OpenTelemetry prend en charge différentes destinations à l’aide de différents exportateurs. Pour plus d’informations sur la configuration d’OpenTelemetry, consultez le guide de prise en main d’OpenTelemetry.

Collecter des traces à l’aide d’Application Insights

Les données de télémétrie de suivi distribué sont automatiquement capturées après la configuration du SDK Application Insights pour les applications ASP.NET ou ASP.NET Core, ou en activant l’instrumentation sans code.

Pour plus d’informations, consultez la documentation sur le suivi distribué Application Insights.

Notes

Actuellement, Application Insights prend uniquement en charge la collecte d’instrumentation d’activités connues spécifiques et ignore les nouvelles activités ajoutées par l’utilisateur. Application Insights offre TrackDependency en tant qu’API spécifique au fournisseur pour ajouter des informations personnalisées en lien avec le suivi distribué.

Collecter des traces à l’aide d’une logique personnalisée

Les développeurs sont libres de créer leur propre logique de collecte personnalisée pour les données de trace d’activité. Cet exemple collecte les données de télémétrie à l’aide de l’API System.Diagnostics.ActivityListener fournie par .NET et les imprime dans la console.

Prérequis

Créer un exemple d’application

Tout d’abord, vous allez créer un exemple d’application qui a une instrumentation de trace distribuée, mais aucune donnée de trace n’est collectée.

dotnet new console

Les API de suivi distribuées nécessaires sont déjà incluses dans les applications qui ciblent .NET 5 et versions ultérieures. Pour les applications ciblant des versions antérieures de .NET, ajoutez le package NuGet System.Diagnostics.DiagnosticSource version 5 ou ultérieure.

dotnet add package System.Diagnostics.DiagnosticSource

Remplacez le contenu du fichier Program.cs généré par cet exemple de source :

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Sample.DistributedTracing
{
    class Program
    {
        static ActivitySource s_source = new ActivitySource("Sample.DistributedTracing");

        static async Task Main(string[] args)
        {
            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

        static async Task DoSomeWork()
        {
            using (Activity a = s_source.StartActivity("SomeWork"))
            {
                await StepOne();
                await StepTwo();
            }
        }

        static async Task StepOne()
        {
            using (Activity a = s_source.StartActivity("StepOne"))
            {
                await Task.Delay(500);
            }
        }

        static async Task StepTwo()
        {
            using (Activity a = s_source.StartActivity("StepTwo"))
            {
                await Task.Delay(1000);
            }
        }
    }
}

L’exécution de l’application ne collecte pas encore de données de trace :

> dotnet run
Example work done

Ajouter du code pour collecter les traces

Mettez à jour Main() avec ce code :

        static async Task Main(string[] args)
        {
            Activity.DefaultIdFormat = ActivityIdFormat.W3C;
            Activity.ForceDefaultIdFormat = true;

            Console.WriteLine("         {0,-15} {1,-60} {2,-15}", "OperationName", "Id", "Duration");
            ActivitySource.AddActivityListener(new ActivityListener()
            {
                ShouldListenTo = (source) => true,
                Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllDataAndRecorded,
                ActivityStarted = activity => Console.WriteLine("Started: {0,-15} {1,-60}", activity.OperationName, activity.Id),
                ActivityStopped = activity => Console.WriteLine("Stopped: {0,-15} {1,-60} {2,-15}", activity.OperationName, activity.Id, activity.Duration)
            });

            await DoSomeWork();
            Console.WriteLine("Example work done");
        }

La sortie inclut à présent la journalisation :

> dotnet run
         OperationName   Id                                                           Duration
Started: SomeWork        00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01
Started: StepOne         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-a7c77a4e9a02dc4a-01
Stopped: StepOne         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-a7c77a4e9a02dc4a-01      00:00:00.5093849
Started: StepTwo         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-9210ad536cae9e4e-01
Stopped: StepTwo         00-bdb5faffc2fc1548b6ba49a31c4a0ae0-9210ad536cae9e4e-01      00:00:01.0111847
Stopped: SomeWork        00-bdb5faffc2fc1548b6ba49a31c4a0ae0-c447fb302059784f-01      00:00:01.5236391
Example work done

Il est facultatif de définir DefaultIdFormat et ForceDefaultIdFormat, mais cela permet de s’assurer que l’exemple produit une sortie similaire sur différentes versions du runtime .NET. .NET 5 utilise le format d’ID TraceContext W3C par défaut, mais les versions antérieures de .NET utilisent le format d’ID Hierarchical. Pour plus d’informations, consultez la page sur les ID d’activité.

System.Diagnostics.ActivityListener est utilisé pour recevoir des rappels pendant la durée de vie d’une activité.

  • ShouldListenTo - Chaque activité est associée à un ActivitySource, qui agit comme son espace de noms et son producteur. Ce rappel est appelé une fois pour chaque ActivitySource dans le processus. Retourne la valeur True si vous souhaitez effectuer un échantillonnage ou être informé des événements de démarrage/arrêt pour les activités produites par cette source.
  • Sample - Par défaut, StartActivity ne crée pas d’objet d’activité, sauf si un ActivityListener indique qu’il doit être échantillonné. La valeur AllDataAndRecorded indique que l’activité doit être créée, que IsAllDataRequested doit être définie sur True et que l’indicateur Recorded est défini pour ActivityTraceFlags. IsAllDataRequested peut être observé par le code instrumenté comme indicateur qu’un écouteur souhaite s’assurer que les informations d’activité auxiliaires telles que les balises et les événements sont renseignées. L’indicateur enregistré est encodé dans l’ID TraceContext W3C et indique à d’autres processus impliqués dans la trace distribuée que cette trace doit être échantillonnée.
  • ActivityStarted et ActivityStopped sont appelés lorsqu’une activité est démarrée et arrêtée respectivement. Ces rappels permettent d’enregistrer des informations pertinentes sur l’activité ou éventuellement de les modifier. Lorsqu’une activité vient de démarrer, la plupart des données peuvent toujours être incomplètes et elles sont renseignées avant l’arrêt de l’activité.

Une fois qu’un ActivityListener a été créé et que les rappels sont renseignés, le fait d’appeler ActivitySource.AddActivityListener(ActivityListener) lance l’appel des rappels. Appelez ActivityListener.Dispose() pour arrêter le flux de rappels. N’oubliez pas que dans le code multithread, les notifications de rappel en cours peuvent être reçues pendant que Dispose() est exécuté ou même peu après qu’il a été retourné.