使用 OpenTelemetry、OTLP 和 Aspire 儀表板

本文將教你如何使用 OpenTelemetry 進行 .NET 網頁 API 的儀器化,並透過 OTLP 將日誌、指標和追蹤資料傳送到Aspire儀表板。 你加入 OpenTelemetry 套件,設定自訂指標與追蹤,並在儀表板中查看結果。

Aspire儀表板是 Aspire 的標準組成部分,但也可作為獨立的 Docker 容器提供,並提供可用於傳送遙測資料的 OTLP 端點。 儀表板可視覺化日誌、指標與追蹤資料。 這樣使用儀表板時,不會依賴 Aspire,且它能視覺化任何透過 OTLP 傳送遙測的應用程式的遙測數據。 只要能將遙測資料傳送到 OTLP 端點,這方法同樣適用於用 Java、Go 或 Python 撰寫的應用程式。

儀表板 Aspire 所需的設定與設定步驟比起開源解決方案如 Prometheus、Grafana 和 Jaeger 更少。 但與這些工具不同的是, Aspire 儀表板是開發者視覺化工具,而非生產監控工具。

1. 建立專案

使用 Visual Studio 中的 ASP.NET Core Empty 範本或使用下列 .NET CLI 命令,建立簡單的 Web API 專案:

dotnet new web

2. 參考 OpenTelemetry 套件

要新增 OpenTelemetry 套件,請使用 NuGet 封裝管理員,或執行以下dotnet add package指令:

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http

或者,您也可以直接將以下 PackageReference 項目加入專案檔案:

<ItemGroup>
  <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.19.1" />
  <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.19.1" />
  <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.19.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.19.0" />
</ItemGroup>

注意

因為 OTel API 不斷演進,建議使用最新版本。

3. 使用指令加法

請在檔案頂端新增以下 using 指令:

using System.Diagnostics;
using System.Diagnostics.Metrics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

4. 新增指標與活動定義

以下程式碼定義了一個新的指標(greetings.count),用來計算客戶端呼叫 API 的次數,以及一個新的活動來源(Otel.Example)。 請在 builder.Build 前插入此程式碼:

// Custom metrics for the application
var greeterMeter = new Meter("OTel.Example", "1.0.0");
var countGreetings = greeterMeter.CreateCounter<int>("greetings.count", description: "Counts the number of greetings");

// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OTel.Example");

5. 配置 OpenTelemetry 並使用正確的提供者

在 builder.Build 前面插入下列程式碼:

// Configure the shared OTLP connection used by logs, metrics, and traces.
var otlpEndpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]!);
Action<OtlpExporterOptions> configureOtlp = options =>
{
    options.Endpoint = otlpEndpoint;
    options.Protocol = OtlpExportProtocol.Grpc;
    options.Headers = builder.Configuration["OTEL_EXPORTER_OTLP_HEADERS"]; // To secure endpoint (not in this example)
};

// Setup logging to be exported via OpenTelemetry
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.IncludeFormattedMessage = true;
    logging.IncludeScopes = true;
    logging.AddOtlpExporter(configureOtlp);
});

var otel = builder.Services.AddOpenTelemetry();

// Identify this application as a single service in the Aspire dashboard.
otel.ConfigureResource(resource => resource.AddService(builder.Configuration["OTEL_SERVICE_NAME"]!));

// Add Metrics for ASP.NET Core and our custom metrics and export via OTLP
otel.WithMetrics(metrics =>
{
    // Metrics provider from OpenTelemetry
    metrics.AddAspNetCoreInstrumentation();

    // Our custom metrics
    metrics.AddMeter(greeterMeter.Name);

    // Metrics provided by ASP.NET Core in .NET
    metrics.AddMeter("Microsoft.AspNetCore.Hosting");
    metrics.AddMeter("Microsoft.AspNetCore.Server.Kestrel");

    // Export the metrics via OTLP
    metrics.AddOtlpExporter(configureOtlp);
});

// Add Tracing for ASP.NET Core and our custom ActivitySource and export via OTLP
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
    tracing.AddOtlpExporter(configureOtlp);
});

此程式碼會使用不同的遙測資料來源來設定 OpenTelemetry:

  • 它會將一個 OTel 提供者新增至 ILogger 以收集日誌記錄。
  • 它會設定計量,並註冊 ASP.NET 和自訂測量器的檢測提供者與測量器。
  • 它會設定追蹤,註冊檢測提供者以及自訂 ActivitySource。

接著它會註冊 OTLP 匯出器,並利用環境變數來設定。

6. 配置 OTLP 設定

你可以透過程式碼、環境變數或應用程式設定中的 API,來設定 OTLP 匯出器。 在此範例中,請在 Logging 區段之後,於 appsettings.Development.json 的根層級加入 OTLP 設定:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317",
  "OTEL_SERVICE_NAME": "OTLP-Example"
}

為 .NET OTLP 匯出器或常見 OTel 設定新增其他設定,例如OTEL_RESOURCE_ATTRIBUTES定義資源屬性。

注意

ASP.NET Core 同時載入 appsettings.json 和 appsettings.Development.json。 當您在 Development 環境中執行應用程式時,appsettings.Development.json 中的設定會覆寫 appsettings.json 中的重複設定。

7. 建立 API 端點

在 app.Run() 和 builder.Build 之間插入以下程式碼:

app.MapGet("/", SendGreeting);

在檔案底部插入下列函數:

async Task<string> SendGreeting(ILogger<Program> logger)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");

    // Log a message
    logger.LogInformation("Sending greeting");

    // Increment the custom counter
    countGreetings.Add(1);

    // Add a tag to the Activity
    activity?.SetTag("greeting", "Hello World!");

    return "Hello World!";
}

注意

端點定義並未使用任何 OpenTelemetry 專用的東西。 它使用 .NET API 來實現可觀察性。

8. 啟動 Aspire 儀表板容器

用 docker 來下載並執行儀表板容器。

docker run --rm -it `
-p 18888:18888 `
-p 4317:18889 `
--name aspire-dashboard `
mcr.microsoft.com/dotnet/aspire-dashboard:latest

儀表板中顯示的資料可能包含敏感資訊。 預設情況下,儀表板需要驗證令牌才能登入。 容器會在輸出中顯示此標記。

Aspire 儀表板

複製網址,替換0.0.0.0成 ,例如http://localhost:18888/login?t=123456780abcdef123456780,localhost然後在瀏覽器中開啟。 或者,在登入對話框後 /login?t= 面貼上金鑰。 每次啟動容器時,代幣都會改變。

9. 負責專案

使用 dotnet run 執行專案。 控制台輸出會顯示應用程式正在接聽的 URL,例如:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5086

請使用你自己控制台輸出中顯示的埠,因為這可能與本文的範例不同。 使用瀏覽器或 curl 來存取該埠的 API:

curl -k http://localhost:5086

每次你請求該頁面,問候數量就會增加。

9.1 日誌輸出

程式碼使用 ILogger 記錄陳述式。 預設情況下,.NET 啟用 Console Provider,該提供者會將輸出導向控制台。

你可以透過幾種方式從 .NET 匯出記錄:

  • 像 Kubernetes 這類容器系統會重新導向 stdout 並 stderr 輸出到日誌檔案。
  • 使用能與 整合的 ILogger日誌函式庫,例如 Serilog 和 NLog。
  • 使用用於 OTel 的日誌提供者,例如 OTLP。 步驟 5 中程式碼的記錄區段會加入 OTel 提供者。

儀表板會將日誌顯示為結構化日誌。 你在日誌訊息中設定的任何屬性都會變成日誌記錄中的欄位。

獨立儀表板中的記錄

9.2 指標檢視

Aspire 儀表板會以各個資源為單位顯示指標。 資源是 OTel 中指遙測來源的術語,例如程序。 當你選擇資源時,儀表板會列出該資源傳送到其 OTLP 端點的每個指標。 指標清單是動態的,隨著儀表板接收新指標而更新。

獨立儀表板中的指標

指標檢視取決於你使用的指標類型:

  • 儀表板會直接顯示數值。
  • 對於針對每個請求追蹤一個數值的直方圖,例如請求耗時或每個請求傳送的位元組數,儀表板會將這些數值彙整到一系列分桶中,並繪製 P50、P90 和 P99 百分位數圖表。 直方圖結果可包含示例,也就是個別資料點以及該請求的追蹤/跨度 ID。 儀表板會在圖表上將這些顯示為點。 選取其中一個以前往對應的追蹤記錄,這樣你就能查看導致該值的原因。 此功能可協助您找出並診斷異常值。
  • 計量可以包含維度,這些維度是與個別值相關聯的索引鍵/值組。 儀表板會依維度彙整數值。 使用檢視中的下拉式選單,依特定維度來篩選結果,例如只顯示 GET 要求,或 ASP.NET 中的特定 URL 路由。

9.3 追蹤視圖

追蹤檢視會列出痕跡。 每個追蹤是一組共享相同追蹤 ID 的活動。 跨度用於追蹤工作,而每個跨度都代表一個工作單位。 處理 ASP.NET 請求會產生一個區間。 提出 HttpClient 請求是一個時間範圍操作。 透過追蹤每個跨度的父跨,你可以建立一個可視覺化的跨度階層。 當你從每個資源(處理程序)收集跨度時,就可以追蹤橫跨一系列服務的工作。 HTTP 請求包含一個標頭,將追蹤 ID 與父 span ID 傳遞給下一個服務。 每個資源必須收集遙測資料並傳送給同一個收集器,該收集器再彙整並呈現跨度的階層結構。

獨立儀表板中的追蹤

儀表板會顯示一份帶有摘要資訊的痕跡清單。 每當儀表板偵測到帶有新追蹤 ID 的跨度時,就會在表格中新增一列。 選擇 「檢視 」以顯示描圖中的所有跨度。

獨立儀表板中的範圍

選擇一個區間以顯示其細節,包括該區間的任何屬性,例如你在步驟 7 中設定的greeting標籤。