本文適用於:✔️ .NET 6.0 和更新版本 ✔️ .NET Framework 4.6.1 和更新版本
檢測的程式代碼可以記錄數值度量,但測量通常需要匯總、傳輸和儲存,以建立實用的監視計量。 匯總、傳輸和儲存數據的程序稱為收集。 本教學課程示範數個收集計量的範例:
- 使用 OpenTelemetry 和 Prometheus 在 Grafana 中填入計量。
- 即時查看指標
dotnet-counters
- 使用基礎 .NET MeterListener API 建立自定義收集工具。
如需自定義計量檢測和選項的詳細資訊,請參閱 比較計量 API。
先決條件
- .NET 6.0 SDK 或更新版本
建立範例應用程式
必須先進行測量,才能收集指標。 本教學課程會建立具有基本計量檢測的應用程式。 .NET 運行時間也有 內建的各種計量。 如需使用 System.Diagnostics.Metrics.Meter API 建立新計量的詳細資訊,請參閱 檢測教學課程。
dotnet new console -o metric-instr
cd metric-instr
dotnet add package System.Diagnostics.DiagnosticSource
以下列程式碼取代 Program.cs
的內容:
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>("hats-sold");
static void Main(string[] args)
{
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
}
上述程式代碼會以隨機間隔和隨機時間模擬銷售帽子。
使用 dotnet-counters 檢視指標
dotnet-counters 是命令行工具,可視需要檢視 .NET Core 應用程式的即時計量。 它不需要設定,因此適合用於臨機作調查,或驗證計量檢測是否正常運作。 它適用於基於 System.Diagnostics.Metrics 的 API 和 EventCounters。
如果未安裝 dotnet-counters 工具,請執行下列命令:
dotnet tool update -g dotnet-counters
當範例應用程式正在執行時,請啟動 dotnet-counters。 以下命令顯示如何使用 dotnet-counters
監控來自HatCo.HatStore
計量器的所有指標範例。 計量名稱會區分大小寫。 我們的範例應用程式名為 metric-instr.exe,請將其替換為您自己的範例應用程式名稱。
dotnet-counters monitor -n metric-instr HatCo.HatStore
類似如下所示的輸出會顯示:
Press p to pause, r to resume, q to quit.
Status: Running
[HatCo.HatStore]
hats-sold (Count / 1 sec) 4
dotnet-counters
可以使用不同的一組度量來執行,以查看 .NET 執行階段的一些內建檢測工具:
dotnet-counters monitor -n metric-instr
類似如下所示的輸出會顯示:
Press p to pause, r to resume, q to quit.
Status: Running
[System.Runtime]
% Time in GC since last GC (%) 0
Allocation Rate (B / 1 sec) 8,168
CPU Usage (%) 0
Exception Count (Count / 1 sec) 0
GC Heap Size (MB) 2
Gen 0 GC Count (Count / 1 sec) 0
Gen 0 Size (B) 2,216,256
Gen 1 GC Count (Count / 1 sec) 0
Gen 1 Size (B) 423,392
Gen 2 GC Count (Count / 1 sec) 0
Gen 2 Size (B) 203,248
LOH Size (B) 933,216
Monitor Lock Contention Count (Count / 1 sec) 0
Number of Active Timers 1
Number of Assemblies Loaded 39
ThreadPool Completed Work Item Count (Count / 1 sec) 0
ThreadPool Queue Length 0
ThreadPool Thread Count 3
Working Set (MB) 30
如需詳細資訊,請參閱 dotnet-counters。 若要深入瞭解 .NET 中的計量,請參閱 內建計量。
使用 OpenTelemetry 和 Prometheus 檢視 Grafana 中的計量
概觀
- 這是 Cloud Native Computing Foundation 所支援的廠商中性開放原始碼專案。
- 標準化為雲端原生軟體產生和收集遙測資料。
- 使用 .NET 計量 API 進行操作。
- 由 Azure 監視器 和許多 APM(應用程式效能管理)廠商支持。
本教程展示如何使用 OSS Prometheus 和 Grafana 專案來整合 OpenTelemetry 度量。 計量數據流:
.NET 計量 API 會記錄來自範例應用程式的度量。
在應用程式中執行的 OpenTelemetry 連結庫會匯總度量。
Prometheus 匯出工具連結庫會透過 HTTP 計量端點提供匯總的數據。 'Exporter' 是 OpenTelemetry 中用來將遙測數據傳輸到廠商特定後端的程式庫。
Prometheus 伺服器:
- 輪詢計量端點
- 讀取數據
- 將數據儲存在資料庫中以供長期保存。 Prometheus 是指將數據讀取和儲存為 擷取 端點。
- 可以在不同的電腦上執行
Grafana 伺服器:
- 查詢儲存在 Prometheus 中的數據,並將其顯示在 Web 型監視儀錶板上。
- 可以在不同的電腦上執行。
設定範例應用程式以使用 OpenTelemetry 的 Prometheus 匯出工具
將 OpenTelemetry Prometheus 匯出工具的參考新增至範例應用程式:
dotnet add package OpenTelemetry.Exporter.Prometheus.HttpListener --prerelease
備註
撰寫本文時,本教學課程使用的是當時可用的 OpenTelemetry Prometheus 支援的預發行版本。
使用 OpenTelemetry 組態進行更新 Program.cs
:
using OpenTelemetry;
using OpenTelemetry.Metrics;
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(
name: "hats-sold",
unit: "Hats",
description: "The number of hats sold in our store");
static void Main(string[] args)
{
using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("HatCo.HatStore")
.AddPrometheusHttpListener(options => options.UriPrefixes = new string[] { "http://localhost:9184/" })
.Build();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0,1000));
}
}
}
在上述程式碼中:
-
AddMeter("HatCo.HatStore")
配置 OpenTelemetry 以傳輸應用程式中的 Meter 所定義的所有度量。 -
AddPrometheusHttpListener
將 OpenTelemetry 設定為:- 在
9184
埠公開 Prometheus 的度量端點 - 使用 HttpListener。
- 在
如需 OpenTelemetry 組態選項的詳細資訊,請參閱 OpenTelemetry 檔 。 OpenTelemetry 檔案顯示 ASP.NET 應用程式的裝載選項。
執行應用,讓它持續運行以便收集數據:
dotnet run
設置及設定 Prometheus
請遵循 Prometheus 第一個步驟來設定 Prometheus 伺服器,並確認其運作正常。
修改 prometheus.yml 組態檔,讓 Prometheus 會擷取範例應用程式公開的計量端點。 在 scrape_configs
區段中新增下列反白顯示的文字:
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]
- job_name: 'OpenTelemetryTest'
scrape_interval: 1s # poll very quickly for a more responsive demo
static_configs:
- targets: ['localhost:9184']
啟動 Prometheus
重載設定或重新啟動 Prometheus 伺服器。
確認 OpenTelemetryTest 在 Prometheus 入口網站的 [ 狀態>目標 ] 頁面中處於 UP 狀態。
在 Prometheus 入口網站的 [圖形] 頁面上,於表達式文本框中輸入
hats
,然後在 [圖表] 索引標籤中選取hats_sold_Hats
,Prometheus 會顯示範例應用程式所發出之「hats-sold」計數器的遞增變化。
在上圖中,圖表時間會設定為 5m,也就是5分鐘。
如果 Prometheus 伺服器尚未長時間擷取範例應用程式,您可能需要等候數據累積。
在 Grafana 儀錶板上顯示計量
請遵循 標準指示 來安裝 Grafana,並將其連線到 Prometheus 數據源。
點擊 Grafana 網頁入口左側工具列上的 + 圖示,然後選擇 儀錶板,以建立 Grafana 儀錶板。 在出現的儀錶板編輯器中,於 標題 輸入框中輸入 Hats Sold/Sec,並在 PromQL 表達式欄位中輸入 rate(hats_sold[5m]):
按兩下 [套用 ] 以儲存並檢視新的儀錶板。
]
使用 .NET MeterListener API 建立自定義收集工具
.NET MeterListener API 可讓您建立自訂的內部處理邏輯,以觀察由 System.Diagnostics.Metrics.Meter 記錄的度量。 如需建立與舊版 EventCounters 檢測相容的自定義邏輯指引,請參閱 EventCounters。
修改 Program.cs
的代碼以使用 MeterListener:
using System.Diagnostics.Metrics;
class Program
{
static Meter s_meter = new("HatCo.HatStore", "1.0.0");
static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(
name: "hats-sold",
unit: "Hats",
description: "The number of hats sold in our store");
static void Main(string[] args)
{
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
meterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);
// Start the meterListener, enabling InstrumentPublished callbacks.
meterListener.Start();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
static void OnMeasurementRecorded<T>(
Instrument instrument,
T measurement,
ReadOnlySpan<KeyValuePair<string, object?>> tags,
object? state)
{
Console.WriteLine($"{instrument.Name} recorded measurement {measurement}");
}
}
以下輸出顯示應用程式在每個測量上使用自定義回調的結果:
> dotnet run
Press any key to exit
hats-sold recorded measurement 978
hats-sold recorded measurement 775
hats-sold recorded measurement 666
hats-sold recorded measurement 66
hats-sold recorded measurement 914
hats-sold recorded measurement 912
...
說明範例程序代碼
本節中的代碼段來自上述範例。
在下列醒目提示的程式碼中,會建立一個 MeterListener 實例來接收度量。 關鍵詞using
會在Dispose
超出範圍時呼叫meterListener
。
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
下列高亮顯示的程式碼設定接收測量數據的監聽器所接收的儀器。 InstrumentPublished 是在應用程式內建立新工具時所調用的委託事件。
using MeterListener meterListener = new();
meterListener.InstrumentPublished = (instrument, listener) =>
{
if (instrument.Meter.Name is "HatCo.HatStore")
{
listener.EnableMeasurementEvents(instrument);
}
};
委任代表可以檢查文件,以決定是否要訂閱。 例如,委託可以檢查名稱、計量器或任何其他公用屬性。 EnableMeasurementEvents 可接收來自指定儀器的度量。 透過另一種方法取得對儀器的參考的程式碼:
- 通常不會這樣做。
- 可以隨時使用參考來呼叫
EnableMeasurementEvents()
。
藉由呼叫 SetMeasurementEventCallback 來設定接收儀器度量數據時所調用的委派:
meterListener.SetMeasurementEventCallback<int>(OnMeasurementRecorded);
// Start the meterListener, enabling InstrumentPublished callbacks.
meterListener.Start();
var rand = Random.Shared;
Console.WriteLine("Press any key to exit");
while (!Console.KeyAvailable)
{
//// Simulate hat selling transactions.
Thread.Sleep(rand.Next(100, 2500));
s_hatsSold.Add(rand.Next(0, 1000));
}
}
static void OnMeasurementRecorded<T>(
Instrument instrument,
T measurement,
ReadOnlySpan<KeyValuePair<string, object?>> tags,
object? state)
{
Console.WriteLine($"{instrument.Name} recorded measurement {measurement}");
}
泛型參數會控制回呼所接收的度量數據類型。 例如, Counter<int>
會產生 int
度量, Counter<double>
會產生 double
度量。 可使用byte
、short
、int
、long
、float
、double
和decimal
類型來創建儀器。 除非您瞭解不是所有數據類型都需要的情況,否則我們建議您為每個數據類型註冊回呼。 對 SetMeasurementEventCallback
使用不同泛型參數進行重複呼叫可能會顯得有些不尋常。 API 的設計方式是為了讓 MeterListener
接收具有低效能負擔的測量,通常只需要幾奈秒。
當呼叫MeterListener.EnableMeasurementEvents
時,可以提供一個state
物件作為其中一個參數。 物件 state
是任意的。 如果您在該次呼叫中提供狀態物件,則會將其與該工具一起儲存,並在回呼中以 state
參數的形式返回給您。 這既是為了方便又作為效能優化。 聽眾通常需要:
- 為每個將測量值儲存於記憶體中的儀器建立物件。
- 使用程式碼對這些測量值進行計算。
或者,建立一個 Dictionary
來將儀器映射到儲存物件,並在每次測量時查詢它。 使用Dictionary
比從 state
進行存取要慢得多。
meterListener.Start();
以上程式碼會啟動 MeterListener
,從而啟用回呼功能。 程序中的每個預存 Instrument 都會調用委派 InstrumentPublished
。 新建立的 Instrument 物件也會觸發 InstrumentPublished
被調用。
using MeterListener meterListener = new MeterListener();
當應用程式完成接聽時,釋放接聽器會停止回呼流程,並釋放對接聽器物件的任何內部參照。 宣告using
時使用的meterListener
關鍵詞會在該變數Dispose
超出作用域時被呼叫。 請注意,Dispose
僅承諾不會啟動新的回呼。 因為回呼發生在不同的執行緒上,因此即使在呼叫 Dispose
傳回之後,仍然可能有回呼正在進行中。
若要保證回呼中的特定程式代碼區域目前未執行,且未來不會執行,則必須新增線程同步處理。
Dispose
預設不會包含同步處理,因為:
- 同步處理會在每個度量回呼中增加額外的效能負擔。
-
MeterListener
設計為注重效能的 API。