Teilen über


Erfassen einer verteilten Ablaufverfolgung

Dieser Artikel gilt für: ✔️ .NET Core 2.1 und höhere Versionen ✔️ .NET Framework 4.5 und höhere Versionen

Instrumentierter Code kann Activity-Objekte als Teil einer verteilten Ablaufverfolgung erstellen, aber die Informationen in diesen Objekten müssen in einem zentralen Speicher gesammelt werden, damit die gesamte Ablaufverfolgung später überprüft werden kann. In diesem Tutorial erfassen Sie verteilte Ablaufverfolgungstelemetrie auf unterschiedliche Weise, sodass sie bei Bedarf zur Diagnose von Anwendungsproblemen zur Verfügung steht. Wenn Sie eine neue Instrumentierung hinzufügen möchten, lesen Sie das Instrumentierungstutorial.

Erfassen von Ablaufverfolgungen mithilfe von OpenTelemetry

OpenTelemetry ist ein herstellerneutrales Open-Source-Projekt, das von der Cloud Native Computing Foundation unterstützt wird und zum Ziel hat, die Generierung und Erfassung von Telemetrie für cloudnative Software zu standardisieren. In diesen Beispielen sammeln Sie Informationen zur verteilten Ablaufverfolgung und zeigen sie auf der Konsole an. Um zu erfahren, wie Sie OpenTelemetry zum Senden von Informationen an andere Ziele konfigurieren, lesen Sie den Leitfaden zu den ersten Schritten mit OpenTelemetry.

ASP.NET-Beispiel

Voraussetzungen

Erstellen einer Beispielanwendung

Erstellen Sie zuerst eine neue ASP.NET-Web-App, die als Demoanwendung verwendet werden soll.

dotnet new webapp

Diese App zeigt eine Webseite an, aber beim Durchsuchen der Seite werden noch keine verteilten Ablaufverfolgungsinformationen gesammelt.

Konfigurieren der Sammlung

Um OpenTelemetry zu verwenden, müssen Sie Verweise auf verschiedene NuGet-Pakete hinzufügen.

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

Hinweis

Als dieser Artikel verfasst wurde, war der Build „1.4.0 Release Candidate 1“ die neueste verfügbare Version von OpenTelemetry. Wenn eine endgültige Version verfügbar ist, verwenden Sie diese.

Ändern Sie als Nächstes den Quellcode in Program.cs folgendermaßen:

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

Führen Sie die App aus, und navigieren Sie in einem Webbrowser zu der Webseite, die gehostet wird. Nachdem Sie die verteilte OpenTelemetry-Ablaufverfolgung aktiviert haben, sollten in der Konsole Informationen zu den Browserwebanforderungen ausgegeben werden:

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

Die gesamte OpenTelemetry-Konfiguration erfolgt in den neuen Quellzeilen, die mit builder.Services.AddOpenTelemetry() beginnen. Sie haben .WithTracing(...) verwendet, um die verteilte Ablaufverfolgung zu aktivieren. AddAspNetCoreInstrumentation() hat OpenTelemetry aktiviert, um alle Aktivitäten der verteilten Ablaufverfolgung zu sammeln, die vom ASP.NET Core-Webserver erzeugt werden, und AddConsoleExporter() weist OpenTelemetry an, diese Informationen an die Konsole zu senden. Bei einer weniger trivialen App könnten Sie weitere Instrumentierungsbibliotheken hinzufügen, um auch die Ablaufverfolgung für Datenbankabfragen oder ausgehende HTTP-Anforderungen zu sammeln. In diesem Fall würden Sie auch die Konsolenexportfunktion durch eine Exportfunktion für Jaeger, Zipken oder einen anderen von Ihnen verwendeten Überwachungsdienst ersetzen.

Beispiel für Konsolen-App

Voraussetzungen

Erstellen einer Beispielanwendung

Bevor Telemetriedaten zur verteilten Ablaufverfolgung gesammelt werden kann, müssen Sie diese Daten generieren. Diese Instrumentierung befindet sich häufig in Bibliotheken, aber der Einfachheit halber werden Sie eine kleine App erstellen, die eine Beispielinstrumentierung mit StartActivity enthält. Zu diesem Zeitpunkt findet noch keine Erfassung statt, StartActivity() hat keinen Nebeneffekt und gibt NULL zurück. Weitere Details finden Sie im Instrumentierungstutorial.

dotnet new console

Anwendungen, die auf .NET 5 und höher ausgerichtet sind, verfügen bereits über die erforderlichen verteilten Ablaufverfolgungs-APIs. Fügen Sie für Apps, die auf ältere .NET-Versionen ausgelegt sind, das NuGet-Paket System.Diagnostics.DiagnosticSource (Version 5 oder höher) hinzu.

dotnet add package System.Diagnostics.DiagnosticSource

Ersetzen Sie den Inhalt der generierten Datei „Program.cs“ durch diesen Beispielquellcode:

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

Wenn Sie die App ausführen, werden noch keine Ablaufverfolgungsdaten erfasst:

> dotnet run
Example work done

Konfigurieren der Sammlung

Fügen Sie das NuGet-Paket OpenTelemetry.Exporter.Console hinzu.

dotnet add package OpenTelemetry.Exporter.Console

Aktualisieren Sie „Program.cs“ mit zusätzlichen using-Anweisungen von OpenTelemetry:

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

Aktualisieren Sie Main(), um den TracerProvider von OpenTelemetry zu erstellen:

        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");
        }

Nun erfasst die App verteilte Ablaufverfolgungsinformationen und zeigt sie in der Konsole an:

> 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
Quellen

Im Beispielcode haben Sie AddSource("Sample.DistributedTracing") aufgerufen, damit OpenTelemetry die Aktivitäten erfasst, die von der bereits im Code vorhandenen ActivitySource generiert werden:

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

Telemetrie von einer beliebigen ActivitySource kann durch Aufruf von AddSource() mit dem Namen der Quelle erfasst werden.

Exporter

Der Konsolenexporter ist hilfreich für schnelle Beispiele oder die lokale Entwicklung, aber in einer Produktionsbereitstellung möchten Sie wahrscheinlich Ablaufverfolgungen an einen zentralisierten Speicher senden. OpenTelemetry unterstützt eine Vielzahl von Zielen mit unterschiedlichen Exportern. Weitere Informationen zum Konfigurieren von OpenTelemetry finden Sie im Leitfaden zu den ersten Schritten mit OpenTelemetry.

Erfassen von Ablaufverfolgungen mit Application Insights

Verteilte Ablaufverfolgungstelemetrie wird automatisch nach der Konfiguration des Application Insights SDK (für Apps mit ASP.NET oder ASP.NET Core) oder durch Aktivierung von codefreier Instrumentierung erfasst.

Weitere Informationen finden Sie in der Application Insights-Dokumentation zur verteilten Ablaufverfolgung.

Hinweis

Derzeit unterstützt Application Insights nur das Erfassen einer bestimmten bekannten Aktivitätsinstrumentierung und ignoriert neue Aktivitäten, die vom Benutzer hinzugefügt werden. Application Insights bietet TrackDependency als herstellerspezifische API zum Hinzufügen benutzerdefinierter verteilter Ablaufverfolgungsinformationen.

Erfassen von Ablaufverfolgungen mit benutzerdefinierter Logik

Entwicklern steht es frei, eigene, angepasste Erfassungslogik für Aktivitäts-Ablaufverfolgungsdaten zu erstellen. Dieses Beispiel erfasst Telemetriedaten mithilfe der System.Diagnostics.ActivityListener-API, die von .NET bereitgestellt wird, und gibt sie in der Konsole aus.

Voraussetzungen

Erstellen einer Beispielanwendung

Zunächst erstellen Sie eine Beispielanwendung, die über eine verteilte Ablaufverfolgungsinstrumentierung verfügt, bei der jedoch keine Ablaufverfolgungsdaten erfasst werden.

dotnet new console

Anwendungen, die auf .NET 5 und höher ausgerichtet sind, verfügen bereits über die erforderlichen verteilten Ablaufverfolgungs-APIs. Fügen Sie für Apps, die auf ältere .NET-Versionen ausgelegt sind, das NuGet-Paket System.Diagnostics.DiagnosticSource (Version 5 oder höher) hinzu.

dotnet add package System.Diagnostics.DiagnosticSource

Ersetzen Sie den Inhalt der generierten Datei „Program.cs“ durch diesen Beispielquellcode:

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

Wenn Sie die App ausführen, werden noch keine Ablaufverfolgungsdaten erfasst:

> dotnet run
Example work done

Hinzufügen von Code zum Erfassen der Ablaufverfolgungen

Aktualisieren Sie Main() mit diesem 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");
        }

Die Ausgabe enthält jetzt Protokollierung:

> 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

Das Festlegen von DefaultIdFormat und ForceDefaultIdFormat ist optional, hilft aber sicherzustellen, dass das Beispiel mit verschiedenen .NET-Laufzeitversionen ähnliche Ausgaben generiert. .NET 5 verwendet standardmäßig das W3C-TraceContext-ID-Format, aber frühere .NET-Versionen verwenden standardmäßig das Hierarchical-ID-Format. Weitere Informationen finden Sie unter Aktivitäts-IDs.

System.Diagnostics.ActivityListener wird verwendet, um Rückrufe während der Lebensdauer einer Aktivität zu empfangen.

  • ShouldListenTo: Jede Aktivität ist einer ActivitySource zugeordnet, die als Namespace und Producer fungiert. Dieser Rückruf wird ein Mal für jede ActivitySource im Prozess aufgerufen. Geben Sie TRUE zurück, wenn Sie daran interessiert sind, eine Stichprobenentnahme durchzuführen oder über Start-/Stoppereignisse für von dieser Quelle generierte Aktivitäten benachrichtigt zu werden.
  • Sample: Standardmäßig erstellt StartActivity kein Activity-Objekt, es sei denn, ein ActivityListener gibt an, dass es erfasst werden soll. Die Rückgabe von AllDataAndRecorded gibt an, dass die Aktivität erstellt und IsAllDataRequested auf „true“ festgelegt soll, und ActivityTraceFlags legt das Recorded-Flag fest. IsAllDataRequested kann vom instrumentierten Code als Hinweis darauf beobachtet werden, dass ein Listener sicherstellen möchte, dass zusätzliche Aktivitätsinformationen wie Tags und Ereignisse mit Daten aufgefüllt werden. Das Recorded-Flag ist in der W3C-TraceContext-ID codiert und ein Hinweis für andere an der verteilten Ablaufverfolgung beteiligte Prozesse, dass diese Ablaufverfolgung erfasst werden soll.
  • ActivityStarted und ActivityStopped werden aufgerufen, wenn eine Aktivität gestartet bzw. beendet wird. Diese Rückrufe bieten die Möglichkeit, relevante Informationen zur Aktivität aufzuzeichnen oder diese ggf. zu ändern. Wenn eine Aktivität gerade erst gestartet wurde, sind viele Daten möglicherweise noch unvollständig, und werden vor dem Beenden der Aktivität aufgefüllt.

Sobald ein ActivityListener erstellt wurde und die Rückrufe aufgefüllt werden, initiiert der Aufruf von ActivitySource.AddActivityListener(ActivityListener) das Aufrufen der Rückrufe. Rufen ActivityListener.Dispose() Sie auf, um den Fluss der Rückrufe zu beenden. Beachten Sie, dass in Multithreadcode aktuell ausgeführte Rückrufbenachrichtigungen empfangen werden können, während Dispose() ausgeführt wird, oder sogar sehr kurz nach dessen Rückgabe.