共用方式為


收集分散式追蹤

本文適用於:✔️.NET Core 2.1 和更新版本 ✔️ .NET Framework 4.5 和更新版本

檢測的程式碼可以建立 Activity 物件做為分散式追蹤的一部分,但必須將這些物件中的資訊收集到集中式儲存體中,以便稍後能檢閱整個追蹤。 在本教學課程中,您將以不同的方式收集分散式追蹤遙測,使其能在需要診斷應用程式問題時派上用場。 如果您需要新增檢測,請參閱檢測教學課程

使用 OpenTelemetry 收集追蹤

OpenTelemetryCloud Native Computing Foundation 支援的廠商中立開放原始碼專案,旨在標準化雲端原生軟體遙測的產生和收集。 在這些範例中,您會收集分散式追蹤資訊並將其顯示在主控台上。 若要了解如何設定 OpenTelemetry 以將資訊傳送到其他地方,請參閱 OpenTelemetry 使用者入門指南

ASP.NET 範例

必要條件

建立範例應用程式

首先,建立新的 ASP.NET Web 應用程式來作為示範應用程式。

dotnet new webapp

此應用程式會顯示網頁,但若瀏覽該網頁,您會發現未收集任何分散式追蹤資訊。

設定收集

若要使用 OpenTelemetry,您必須將參考新增至數個 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

注意

撰寫本文時,1.4.0 候選版 1 組建是可用的最新版 OpenTelemetry。 一旦最終版本可供使用,請改用該版本。

接下來,修改 Program.cs 中的原始程式碼,使其看起來像這樣:

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

執行應用程式,並使用網頁瀏覽器來瀏覽至裝載的網頁。 現在您已啟用 OpenTelemetry 分散式追蹤,您應該會看到列印至主控台的瀏覽器網頁要求相關資訊:

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

所有 OpenTelemetry 組態都會發生在以 builder.Services.AddOpenTelemetry() 開頭的新來源行中。 您已使用 .WithTracing(...) 來啟用分散式追蹤。 AddAspNetCoreInstrumentation() 已啟用 OpenTelemetry 來收集 ASP.NET Core 網頁伺服器所產生的所有分散式追蹤活動,且 AddConsoleExporter() 會指示 OpenTelemetry 將該資訊傳送至主控台。 對於較重要的應用程式,您可以新增更多檢測程式庫,以收集資料庫查詢或輸出 HTTP 要求的追蹤。 您也可以將主控台匯出工具取代為適用於 Jaeger、Zipken 或其他所選監視服務的匯出工具。

主控台應用程式範例

必要條件

建立範例應用程式

您必須先產生分散式追蹤遙測,才可以收集這些遙測。 此檢測通常位於程式庫中,但為了簡單起見,您將建立一個小型應用程式,其中包含一些使用 StartActivity 的檢測範例。 此時未發生任何收集動作,而且 StartActivity() 沒有副作用,並傳回 null。 如需詳細資訊,請參閱檢測教學課程

dotnet new console

目標為 .NET 5 和更新版本的應用程式已經包含必要的分散式追蹤 API。 針對以舊 .NET 版本為目標的應用程式,請新增 System.Diagnostics.DiagnosticSource NuGet 套件 第 5 版或更新版本。

dotnet add package System.Diagnostics.DiagnosticSource

以下列範例來源取代產生的 Program.cs 內容:

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

執行應用程式還不會收集任何追蹤資料:

> dotnet run
Example work done

設定收集

新增 OpenTelemetry.Exporter.Console NuGet 套件。

dotnet add package OpenTelemetry.Exporter.Console

使用其他 OpenTelemetry using 指示詞更新 Program.cs:

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

更新 Main() 以建立 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");
        }

現在應用程式會收集分散式追蹤資訊,並將其顯示至主控台:

> 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
來源

在範例程式碼中,您已叫用 AddSource("Sample.DistributedTracing"),讓 OpenTelemetry 擷取 ActivitySource (已存在於程式碼中) 所產生的活動:

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

您可以從任何 ActivitySource 擷取遙測,方法是使用來源的名稱呼叫 AddSource()

出口商

主控台匯出工具有助於提供快速範例或進行本機開發,但在生產部署中,您可能會想要將追蹤傳送至集中式存放區。 OpenTelemetry 支援使用不同匯出工具的各種目的地。 如需設定 OpenTelemetry 的詳細資訊,請參閱 OpenTelemetry 使用者入門指南

使用 Application Insights 收集追蹤

ASP.NETASP.NET Core 應用程式設定 Application Insights SDK 之後,或啟用無程式碼檢測,就會自動擷取分散式追蹤遙測。

如需詳細資訊,請參閱 Application Insights 分散式追蹤文件

注意

目前,Application Insights 僅支援收集特定的已知活動檢測,並且會忽略新的使用者新增活動。 Application Insights 提供 TrackDependency 作為廠商專屬 API,可新增自訂分散式追蹤資訊。

使用自訂邏輯收集追蹤

開發人員可以免費為活動追蹤資料建立自己的自訂收集邏輯。 此範例會使用 .NET 所提供的 System.Diagnostics.ActivityListener API 收集遙測,並將其列印到主控台。

必要條件

建立範例應用程式

首先,您將建立一個範例應用程式,其中包含一些分散式追蹤檢測,但不會收集任何追蹤資料。

dotnet new console

目標為 .NET 5 和更新版本的應用程式已經包含必要的分散式追蹤 API。 針對以舊 .NET 版本為目標的應用程式,請新增 System.Diagnostics.DiagnosticSource NuGet 套件 第 5 版或更新版本。

dotnet add package System.Diagnostics.DiagnosticSource

以下列範例來源取代產生的 Program.cs 內容:

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

執行應用程式還不會收集任何追蹤資料:

> dotnet run
Example work done

新增程式碼以收集追蹤

使用下列程式碼更新 Main():

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

輸出現在會包含記錄:

> 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

設定 DefaultIdFormatForceDefaultIdFormat 為選擇性,但有助於確保範例在不同的 .NET 執行階段版本上產生類似的輸出。 .NET 5 預設會使用 W3C TraceContext 識別碼格式,但舊版 .NET 預設為使用 Hierarchical 識別碼格式。 如需詳細資訊,請參閱活動識別碼

System.Diagnostics.ActivityListener 會用來在活動存留期期間接收回呼。

  • ShouldListenTo - 每個活動都與 ActivitySource 相關聯,其可作為活動的命名空間和產生者。 此回呼會針對程序中的每個 ActivitySource 叫用一次。 如果您想要執行取樣或收到此來源所產生活動的啟動/停止事件通知,則會傳回 true。
  • Sample - 根據預設,StartActivity 不會建立 Activity 物件,除非某些 ActivityListener 指出應該對其進行取樣。 傳回 AllDataAndRecorded 表示應該建立活動、IsAllDataRequested 應設定為 true,而且 ActivityTraceFlags 會設定 Recorded 旗標。 已檢測的程式碼會看到 IsAllDataRequested,這是接聽程式想要確保標籤和事件等輔助活動資訊已填入的提示。 Recorded 旗標會在 W3C TraceContext 識別碼中編碼,而且會提示分散式追蹤中包含的程序在此追蹤中取樣。
  • ActivityStartedActivityStopped 會在分別啟動和停止活動時呼叫。 這些回呼會提供記錄活動相關資訊或可能修改活動的機會。 當活動剛啟動時,大部分的資料可能仍然不完整,而且會在活動停止之前填入。

建立 ActivityListener 並填入回呼之後,呼叫 ActivitySource.AddActivityListener(ActivityListener) 會起始叫用回呼。 呼叫 ActivityListener.Dispose() 以停止回呼的流程。 請注意,在多執行緒程式碼中,您可能會在執行 Dispose() 時或甚至在其傳回後不久,收到進行中的回呼通知。