語言

在 .NET 中設定分散式追蹤

在 .NET 11 及之後版本中,Microsoft.Extensions.Diagnostics.Tracing API 允許你註冊 ActivityListener 實例,並使用規則來選取每個接聽程式所接收的 ActivitySource 和 Activity 實例。 在程式碼中定義規則或從 IConfiguration載入。

Important

追蹤規則僅影響透過此追蹤基礎架構註冊的監聽器。 它們不會影響不相關的 ActivityListener 執行個體,包括遙測匯出器建立和管理的監聽器。 分別設定監聽器或匯出器。

暫存器追蹤

API 可在 Microsoft.Extensions.Diagnostics 套件中使用。 參考 Microsoft.AspNetCore.App 共享框架的應用程式已經包含了組件。

請在IServiceCollection上呼叫AddTracing。 在回呼中:

  • 請呼叫 AddListener 來登記每個接聽程式。 監聽者名稱在設定規則中用來識別監聽者。
  • 透過 ActivityListenerBuilder 配置監聽者的取樣與通知委派。 追蹤基礎設施擁有 ShouldListenTo、來源訂閱,以及監聽器的存留期。
  • 使用包含規則的設定區段呼叫 AddConfiguration。 對於名為 Tracing 的區段,傳遞 configuration.GetSection("Tracing")。

完整範例顯示了這三種呼叫。 .NET 主機在主機啟動時會啟動追蹤訂閱。 如果你使用依賴注入而不使用主機,請解析已註冊的 ActivitySourceFactory 來建構監聽者並啟用它們的訂閱。 完整的範例會直接解析 Factory。

設定追蹤

透過設定或程式碼來設定追蹤規則。 若無規則匹配監聽者、來源、操作與作用域,該組合的追蹤功能仍被禁用。

無需程式碼設定追蹤

對於使用設定的應用程式,可以在 appsettings.json 或其他 Tracing 中新增一個區段。 然後將該段傳遞給 AddConfiguration:

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

以下範例展示了支援的規則區段與規則層級:

{
  "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
        }
      }
    }
  }
}

直接在 EnabledGlobalTracing、EnabledLocalTracing 或 EnabledTracing 章節下方加入規則。 不要新增 Rules 層級。

規則章節

根據來源範圍及規則是否針對某一個接聽程式,選擇規則區塊:

區段 符合條件的監聽器 比對活動來源
EnabledTracing 所有已註冊的監聽器。 全球與在地的來源。
EnabledGlobalTracing 所有已註冊的監聽器。 僅限全域來源。
EnabledLocalTracing 所有已註冊的監聽器。 僅限本機來源。
{Listener}:EnabledTracing 具名監聽器。 全球與在地的來源。
{Listener}:EnabledGlobalTracing 指定的監聽器。 僅限全球來源。
{Listener}:EnabledLocalTracing 已命名的監聽器。 僅限本機來源。

監聽者名稱與傳入的 AddListener名稱相符。 段落名稱和監聽器名稱不區分大小寫。

規則等級

在任何規則章節中,請使用以下其中一種金鑰格式:

鍵值表單 規則層級 比對
Default Default. 每一個來源和操作。
{SourceName} 活動來源。 每項來自相符來源的操作。
{SourceName}:Default 活動來源。 每個操作都與來源比對有關。 此表單允許來源項目同時包含操作規則。
{SourceName}:{OperationName} 操作。 來自相符來源的已命名作業。

將每個葉子值設定為 true 以啟用匹配,或設定為 false 以停用匹配。 例如,前述的配置:

  • 預設會關閉追蹤功能。
  • 啟用名稱以Contoso開頭的來源。
  • 啟用 Contoso.Orders,但停用其 HealthCheck 作業。
  • 啟用一個以 Contoso. 為開頭、以 .Storage 為結尾的來源模式。
  • 新增僅適用於全域來源、本地來源或名為 Console的監聽者 的規則。

使用 Default 作為布林葉。 若 Default 包含操作子節點,則組態將 Default 視為字面上的活動來源名稱。

用程式碼設定追蹤

對傳遞給 AddTracing 的ITracingBuilder呼叫 EnableTracing 和 DisableTracing。

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

省略 sourceName, operationName或 listenerName 以匹配該層級的所有值。 預設情況下,程式化規則同時適用於全域與本地來源。 透過 scopes 引數傳遞 Local、Global 或兩者,以縮小規則範圍。

配置規則與程式化規則組成一個有序規則集。 若同樣具體的規則相衝突,則最後加入的規則獲勝。 因此,當 EnableTracing、DisableTracing 和 AddTracing 加入同樣具體的規則時,AddConfiguration 回呼中的呼叫順序也很重要。

比對活動來源名稱

來源名稱、操作名稱與接聽程式名稱皆使用不區分大小寫的序數比較。 來源名稱規則支援以下比對形式:

  • 空的來源名稱會匹配所有來源。
  • 不含萬用字元的來源名稱會以前綴方式比對。 例如, Contoso 匹配 Contoso.Orders 和 ContosoPayments;匹配器不需要在前綴後加分隔符。
  • 一個有一個 * 萬用字元的來源名稱會對應前綴和後綴。 例如,Contoso.*.Storage 匹配 Contoso.Orders.Storage,但不匹配 Contoso.Orders.Api。
  • 名稱為 * 的來源符合所有來源。

作業名稱完全一致。 他們不使用前綴比對或萬用字元比對。

套用規則優先順序

對於每個監聽者、來源、操作與範圍的組合,追蹤基礎設施會選擇一條匹配的規則。 它會依照下列順序比較配對規則:

  • 針對特定接聽程式的規則優先於所有接聽程式的規則。
  • 原始碼規則優先於預設規則。 若兩個來源表達式相符,則較長的表達式優先。 比較時使用運算式長度,其中包含 * 萬用字元。
  • 操作規則優先於原始碼層級規則。
  • 僅全域或僅本地規則優先於涵蓋兩個範圍的規則。
  • 當所有前述因素相等時,最後一條規則才優先。

比較止於第一個差異。 例如,聽眾專屬的預設規則優先於適用於所有聽者的來源專屬規則,因為會先評估聽者的特定性。

操作規則同時控制來源訂用項目。 當操作規則從該來源啟用至少一項操作時,監聽者會訂閱該預設停用的來源。 監聽器接著回傳 None 並跳過被停用操作的回調。

選擇全球或在地活動來源

追蹤基礎設施區分了兩種活動來源範圍:

  • 全域來源是透過其建構子建立的ActivitySource物件。 EnabledGlobalTracing 規則適用於這些來源。
  • 本地來源是由透過依賴注入解析出的 ActivitySource 所建立的 ActivitySourceFactory。 EnabledLocalTracing 規則適用於該工廠產生的來源項目。

當你想用相依注入容器來管理來源及其追蹤監聽器時,就用 Create 它。 工廠模式的監聽器會忽略由不同工廠模式建立的本機來源。 規則 EnabledTracing 適用於兩種來源類別。

這些範圍只限制由 AddTracing 註冊的聽眾。 獨立的 ActivityListener 會使用自己的 ShouldListenTo 和抽樣回調,即使是針對由 ActivitySourceFactory 創建的活動來源。

重新載入追蹤組態

AddConfiguration 訂閱所提供設定中的變更權杖。 當 設定提供者 支援重新載入並回報變更時,追蹤基礎設施:

  • 重建規則集。
  • 重新整理每個已註冊監聽器的來源訂閱。
  • 將更新後的規則套用於後續活動。

應用程式在重新載入後仍可繼續使用相同的 ActivitySource 實例。 後續活動則使用更新後的規則。

對於不會自動回報變更的可變提供者,請更新設定並呼叫 Reload。 完整範例使用此方法搭配記憶體內配置提供者。

處理無效設定

追蹤配置使用 TryParse 解析值。 它接受 true 和 false,不區分大小寫,並允許前後留白。 它不接受 1、 0、 yes或 on。

設定載入器會默默忽略一個不是有效布林值的葉節點值。 它也會忽略與支援的結構描述不相符的未知或格式錯誤區段。 仔細檢查關鍵名稱,因為這些情況不會產生異常。

一個來源表達式最多只能包含一個 * 萬用字元。 包含多個通配符的規則會在該規則實體化時拋出 ArgumentException,無論是在應用程式啟動時或設定重新載入後。 對於程式規則,None 也會導致 ArgumentOutOfRangeException。

執行範例程式

以下 .NET 11 主控台應用程式會建立一個啟用操作和一個停用操作。 接著更新被停用操作的規則,呼叫 Reload,並透過相同的本地 ActivitySource 再次啟動該操作。

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

C# 與 Visual Basic 範例產生相同的結果:

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

也請參閱