Sprache

Konfigurieren von verteiltem Tracing in .NET

In .NET 11 und höheren Versionen können Sie mit den Microsoft.Extensions.Diagnostics.Tracing APIs ActivityListener Instanzen registrieren und Regeln verwenden, um die ActivitySource- und Activity-Instanzen auszuwählen, die jeder Listener empfängt. Definieren Sie Regeln im Code, oder laden Sie sie aus IConfiguration.

Important

Ablaufverfolgungsregeln wirken sich nur auf Listener aus, die über diese Ablaufverfolgungsinfrastruktur registriert wurden. Sie wirken sich nicht auf nicht verwandte ActivityListener Instanzen aus, einschließlich Listener, die Telemetrieexporteure erstellen und verwalten. Konfigurieren Sie diese Listener oder Exporter separat.

Ablaufverfolgung registrieren

Die APIs sind im Microsoft.Extensions.Diagnostics Paket verfügbar. Apps, die auf das Microsoft.AspNetCore.App freigegebene Framework verweisen, enthalten bereits die Assembly.

Rufen Sie AddTracing auf einer IServiceCollection ab. Im Callback:

  • Rufen Sie AddListener auf, um jeden Listener zu registrieren. Der Listenername identifiziert den Listener in Konfigurationsregeln.
  • Konfigurieren Sie die Sampling- und Benachrichtigungsdelegaten des Listeners über ActivityListenerBuilder. Die Ablaufverfolgungsinfrastruktur besitzt ShouldListenTo, Quellabonnements und die Lebensdauer des Listeners.
  • Rufen Sie AddConfiguration mit dem Konfigurationsabschnitt auf, der die Regeln enthält. Übergeben Sie für einen Abschnitt mit dem Namen Tracingconfiguration.GetSection("Tracing").

Das vollständige Beispiel zeigt alle drei Aufrufe. Ein .NET Host aktiviert Tracingabonnements, wenn der Host gestartet wird. Wenn Sie Abhängigkeitsinjektion ohne Host verwenden, lösen Sie die registrierten ActivitySourceFactory auf, um die Listener zu erstellen und deren Abonnements zu aktivieren. Im vollständigen Beispiel wird die Factory direkt verwendet.

Konfigurieren der Ablaufverfolgung

Legen Sie Ablaufverfolgungsregeln über die Konfiguration oder im Code fest. Wenn keine Regel mit einem Listener, einer Quelle, einem Vorgang und einem Bereich übereinstimmt, bleibt die Ablaufverfolgung für diese Kombination deaktiviert.

Tracing ohne Code konfigurieren

Fügen Sie für Apps, die die Konfiguration verwenden, einen Tracing Abschnitt zu appsettings.json oder einem anderen Konfigurationsanbieter hinzu. Übergeben Sie diesen Abschnitt dann an AddConfiguration:

tracing.AddConfiguration(configuration.GetSection("Tracing"));

Das folgende Beispiel zeigt die unterstützten Regelabschnitte und Regelebenen:

{
  "Tracing": {
    "EnabledTracing": {
      "Default": false,
      "Contoso": true,
      "Contoso.Orders": {
        "Default": true,
        "HealthCheck": false
      },
      "Contoso.*.Storage": true
    },
    "EnabledGlobalTracing": {
      "System.Net.Http": true
    },
    "EnabledLocalTracing": {
      "Contoso.Workers": true
    },
    "Console": {
      "EnabledLocalTracing": {
        "Contoso.Orders": {
          "Submit": false
        }
      }
    }
  }
}

Fügen Sie Regeln direkt unter einem EnabledTracing, EnabledGlobalTracing oder EnabledLocalTracing Abschnitt hinzu. Fügen Sie keine Rules-Ebene hinzu.

Regelabschnitte

Wählen Sie einen Regelabschnitt basierend auf dem Quellbereich und ob die Regel auf einen Listener ausgerichtet ist:

Abschnitt Passende Listener Abgleich von Aktivitätsquellen
EnabledTracing Alle registrierten Empfänger. Globale und lokale Quellen.
EnabledGlobalTracing Alle registrierten Listener. Nur globale Quellen.
EnabledLocalTracing Alle registrierten Listener. Nur lokale Quellen.
{Listener}:EnabledTracing Der angegebene Listener. Globale und lokale Quellen.
{Listener}:EnabledGlobalTracing Der angegebene Listener. Nur globale Quellen.
{Listener}:EnabledLocalTracing Der angegebene Listener. Nur lokale Quellen.

Listenernamen entsprechen den Namen, die an AddListener übergeben werden. Bei Abschnittsnamen und Listenernamen wird die Groß-/Kleinschreibung nicht beachtet.

Regelebenen

Verwenden Sie unter einem beliebigen Regelabschnitt eines der folgenden Schlüsselformate:

Schlüsselformular Regelstufe Match
Default Standard. Jede Quelle und jeder Vorgang.
{SourceName} Aktivitätsquelle. Jeder Vorgang mit übereinstimmenden Quellen.
{SourceName}:Default Aktivitätsquelle. Jeder Vorgang mit übereinstimmenden Quellen. In diesem Formular kann eine Quelle auch Vorgangsregeln enthalten.
{SourceName}:{OperationName} Operation. Der benannte Vorgang aus passenden Quellen.

Legen Sie jeden Blattwert auf true fest, um die Übereinstimmung zu aktivieren, oder auf false, um sie zu deaktivieren. Zum Beispiel die vorherige Konfiguration:

  • Deaktiviert die Ablaufverfolgung standardmäßig.
  • Aktiviert Quellen, deren Namen mit Contoso beginnen.
  • Aktiviert Contoso.Orders, deaktiviert jedoch dessen HealthCheck-Vorgang.
  • Aktiviert ein Quellmuster, das mit Contoso. beginnt und mit .Storage endet.
  • Fügt Regeln hinzu, die nur für globale Quellen, lokale Quellen oder den Listener mit dem Namen Consolegelten.

Verwenden Sie Default als boolesches Blatt. Wenn Default untergeordnete Vorgangselemente enthält, behandelt die Konfiguration Default als einen Literal-Aktivitätsquellnamen.

Ablaufverfolgung mit Code konfigurieren

Rufen Sie EnableTracing und DisableTracing auf der ITracingBuilder übergeben an AddTracing auf.

tracing.EnableTracing(sourceName: "Contoso");
tracing.DisableTracing(
    sourceName: "Contoso.Orders",
    operationName: "HealthCheck");

Lassen Sie sourceName, operationName oder listenerName weg, um alle Werte auf dieser Ebene abzugleichen. Standardmäßig gilt eine programmgesteuerte Regel sowohl für globale als auch für lokale Quellen. Übergeben Sie Global, Local oder beides über das scopes-Argument, um die Regel einzugrenzen.

Konfigurationsregeln und programmgesteuerte Regeln bilden einen geordneten Regelsatz. Wenn gleich spezifische Regeln in Konflikt geraten, gewinnt die zuletzt hinzugefügte Regel. Die Reihenfolge der Aufrufe im AddTracing Rückruf spielt daher eine Rolle, wenn AddConfiguration, EnableTracing und DisableTracing gleichermaßen spezifische Regeln hinzufügen.

Aktivitätsquellennamen abgleichen

Quellnamen, Vorgangsnamen und Listenernamen verwenden einen ordnungsbasierten Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung. Quellnamenregeln unterstützen diese Übereinstimmungsformen:

  • Ein leerer Quellname entspricht jeder Quelle.
  • Ein Quellname ohne Platzhalter wird anhand des Präfixes abgeglichen. Zum Beispiel entspricht Contoso.OrdersContosoPayments und Contoso; der Matcher erfordert kein Trennzeichen nach dem Präfix.
  • Ein Quellname mit einer *-Wildcard entspricht einem Präfix und einem Suffix. Zum Beispiel entspricht Contoso.*.StorageContoso.Orders.Storage, aber nicht Contoso.Orders.Api.
  • Ein Quellname von * stimmt mit jeder Quelle überein.

Vorgangsnamen stimmen exakt überein. Sie verwenden keinen Präfix- oder Wildcardabgleich.

Regelrangfolge anwenden

Für jede Listener-, Quell-, Vorgangs- und Bereichskombination wählt die Ablaufverfolgungsinfrastruktur eine übereinstimmende Regel aus. Es vergleicht übereinstimmende Regeln in dieser Reihenfolge:

  • Eine listenerspezifische Regel hat Vorrang vor einer Regel für alle Listener.
  • Eine Quellregel hat Vorrang vor einer Standardregel. Wenn zwei Quellausdrücke übereinstimmen, hat der längere Ausdruck Vorrang. Der Vergleich verwendet die Länge des Ausdrucks, einschließlich eines * Wildcards.
  • Eine Operationsregel hat Vorrang vor einer Regel auf Quellcodeebene.
  • Eine ausschließlich globale oder ausschließlich lokale Regel hat Vorrang vor einer Regel, die beide Bereiche abdeckt.
  • Die letzte Regel hat Vorrang, wenn alle vorherigen Faktoren gleich sind.

Der Vergleich endet beim ersten Unterschied. Beispielsweise hat eine listenerspezifische Standardregel Vorrang vor einer quellspezifischen Regel, die für alle Listener gilt, da die Listener-Spezifität zuerst ausgewertet wird.

Betriebsregeln steuern auch Quellabonnements. Ein Listener abonniert eine Quelle, die standardmäßig deaktiviert ist, wenn eine Vorgangsregel mindestens einen Vorgang aus dieser Quelle aktiviert. Der Listener gibt dann None zurück und überspringt seine Rückrufe für deaktivierte Vorgänge.

Globale oder lokale Aktivitätsquellen auswählen

Die Ablaufverfolgungsinfrastruktur unterscheidet zwei Aktivitätsquellenbereiche:

  • Eine globale-Quelle ist ein ActivitySource, das durch seinen Konstruktor erstellt wird. EnabledGlobalTracing-Regeln gelten für diese Quellen.
  • Eine lokale-Quelle ist eine ActivitySourceFactory, erstellt von ActivitySource und aufgelöst von der Abhängigkeitsinjektion. EnabledLocalTracing Regeln gelten für Quellen, die von dieser Factory erstellt wurden.

Verwenden Sie Create, wenn der Container zum Einfügen von Abhängigkeiten die Quelle und die zugehörigen Ablaufverfolgungs-Listener verwalten soll. Die Listener einer Factory ignorieren lokale Quellen, die von einer anderen Factory erstellt wurden. Regeln in EnabledTracing gelten für beide Quelltypen.

Diese Bereiche beschränken nur die Listener, die AddTracing registrieren. Eine unabhängige ActivityListener verwendet eigene ShouldListenTo- und Samplingrückrufe, auch für eine ActivitySource, die von ActivitySourceFactory erstellt wurde.

Tracing-Konfiguration neu laden

AddConfiguration abonniert das Änderungstoken der bereitgestellten Konfiguration. Wenn ein Konfigurationsanbieter das erneute Laden unterstützt und eine Änderung meldet, macht die Ablaufverfolgungsinfrastruktur Folgendes:

  • Erstellt den Regelsatz erneut.
  • Aktualisiert die Quellabonnements jedes registrierten Listeners.
  • Wendet die aktualisierten Regeln auf nachfolgende Aktivitäten an.

Die App kann dieselben ActivitySource Instanzen nach dem Erneutladen weiterhin verwenden. Nachfolgende Aktivitäten verwenden die aktualisierten Regeln.

Aktualisieren Sie für einen veränderbaren Anbieter, der keine Änderungen automatisch meldet, die Konfiguration und rufen Sie Reload auf. Im vollständigen Beispiel wird dieser Ansatz mit dem In-Memory-Konfigurationsanbieter verwendet.

Ungültige Konfiguration behandeln

Die Ablaufverfolgungskonfiguration parst Werte mit TryParse. Sie akzeptiert true und false ohne Rücksicht auf die Groß- und Kleinschreibung und erlaubt den umgebenden Leerraum. Es akzeptiert weder 1, yes, 0 noch on.

Das Konfigurationsladeprogramm ignoriert stillschweigend einen Blattwert, der kein gültiger boolescher Wert ist. Außerdem werden unbekannte oder falsch formatierte Abschnitte ignoriert, die nicht mit dem unterstützten Schema übereinstimmen. Überprüfen Sie die Schlüsselnamen sorgfältig, da diese Fälle keine Ausnahme erzeugen.

Ein Quellausdruck kann höchstens einen * Wildcard enthalten. Eine Regel mit mehreren Wildcards löst ein ArgumentException , wenn die Regel materialisiert wird, entweder während des App-Starts oder nach dem erneuten Laden der Konfiguration. Bei programmgesteuerten Regeln verursacht None ebenfalls ein ArgumentOutOfRangeException.

Beispiel ausführen

Die folgende .NET 11-Konsolen-App erstellt eine aktivierte Operation und eine deaktivierte Operation. Anschließend wird die Regel des deaktivierten Vorgangs aktualisiert, Reload aufgerufen und der Vorgang erneut über denselben lokalen ActivitySource gestartet.

using System.Diagnostics;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.Tracing;

IConfigurationRoot configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["Tracing:EnabledTracing:Default"] = "false",
        ["Tracing:EnabledTracing:Contoso.Orders:Default"] = "true",
        ["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "false",
    })
    .Build();

ServiceCollection services = new();
services.AddTracing(tracing =>
{
    tracing.AddListener("Console", listener =>
    {
        listener.Sample = static (ref ActivityCreationOptions<ActivityContext> _) =>
            ActivitySamplingResult.AllData;
        listener.SampleUsingParentId = static (ref ActivityCreationOptions<string> _) =>
            ActivitySamplingResult.AllData;
        listener.ActivityStarted = activity =>
            Console.WriteLine($"Listener started: {activity.OperationName}");
    });
    tracing.AddConfiguration(configuration.GetSection("Tracing"));
});

using ServiceProvider serviceProvider = services.BuildServiceProvider();
ActivitySourceFactory factory =
    serviceProvider.GetRequiredService<ActivitySourceFactory>();
using ActivitySource source = factory.Create("Contoso.Orders");

Console.WriteLine("Before reload:");
WriteResult(source, "EnabledOperation");
WriteResult(source, "DisabledOperation");

configuration["Tracing:EnabledTracing:Contoso.Orders:DisabledOperation"] = "true";
configuration.Reload();

Console.WriteLine("After reload:");
WriteResult(source, "DisabledOperation");

static void WriteResult(ActivitySource source, string operationName)
{
    using Activity? activity = source.StartActivity(operationName);
    string state = activity is null ? "disabled" : "enabled";
    Console.WriteLine($"{operationName}: {state}");
}
Imports System.Diagnostics
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Diagnostics.Tracing

Module Program
    Sub Main()
        Dim initialData As New Dictionary(Of String, String) From {
            {"Tracing:EnabledTracing:Default", "false"},
            {"Tracing:EnabledTracing:Contoso.Orders:Default", "true"},
            {"Tracing:EnabledTracing:Contoso.Orders:DisabledOperation", "false"}
        }

        Dim configuration As IConfigurationRoot =
            New ConfigurationBuilder().AddInMemoryCollection(initialData).Build()

        Dim services As New ServiceCollection()
        services.AddTracing(
            Sub(tracing)
                tracing.AddListener(
                    "Console",
                    Sub(listener)
                        listener.Sample = AddressOf SampleActivity
                        listener.SampleUsingParentId = AddressOf SampleActivityUsingParentId
                        listener.ActivityStarted =
                            Sub(activity) Console.WriteLine(
                                $"Listener started: {activity.OperationName}")
                    End Sub)
                tracing.AddConfiguration(configuration.GetSection("Tracing"))
            End Sub)

        Using serviceProvider As ServiceProvider = services.BuildServiceProvider()
            Dim factory As ActivitySourceFactory =
                serviceProvider.GetRequiredService(Of ActivitySourceFactory)()

            Using source As ActivitySource = factory.Create("Contoso.Orders")
                Console.WriteLine("Before reload:")
                WriteResult(source, "EnabledOperation")
                WriteResult(source, "DisabledOperation")

                configuration(
                    "Tracing:EnabledTracing:Contoso.Orders:DisabledOperation") = "true"
                configuration.Reload()

                Console.WriteLine("After reload:")
                WriteResult(source, "DisabledOperation")
            End Using
        End Using
    End Sub

    Private Function SampleActivity(
        ByRef options As ActivityCreationOptions(Of ActivityContext)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Function SampleActivityUsingParentId(
        ByRef options As ActivityCreationOptions(Of String)
    ) As ActivitySamplingResult
        Return ActivitySamplingResult.AllData
    End Function

    Private Sub WriteResult(source As ActivitySource, operationName As String)
        Using activity As Activity = source.StartActivity(operationName)
            Dim state As String = If(activity Is Nothing, "disabled", "enabled")
            Console.WriteLine($"{operationName}: {state}")
        End Using
    End Sub
End Module

Die Beispiele C# und Visual Basic erzeugen dasselbe Ergebnis:

Before reload:
Listener started: EnabledOperation
EnabledOperation: enabled
DisabledOperation: disabled
After reload:
Listener started: DisabledOperation
DisabledOperation: enabled

Siehe auch