1. 介紹
假設你是網站管理員,每天有一千個使用者來訪。在日誌中你看到一切正常,幾乎沒有錯誤(最多有人偶爾忘記密碼或輸入 captcha 錯誤)。「一切都很好!」——你這麼想。
然後有人寫信到客服:網站卡得要死,頁面要 10 秒才開。你去看日誌——沒有錯誤!太棒了?不,因為日誌告訴你發生了什麼(或沒發生),但不會告訴你有多快或多慢、為此用了多少資源,以及在負載增加時這些行為如何變化。
這時候就輪到指標上場——可以量化的應用運行特性。它們不只是錯誤數,還有平均響應時間、記憶體使用量、每秒請求數等,可以據此判斷系統健康狀況。
比較:
日誌 — 是 "發生了什麼"。
指標 — 是 "系統運作得好還是不好"。
追蹤 — 是 "為何系統會這樣運作(細節)"。
有哪些指標,該蒐集哪些?
主要的指標類型:
| 指標類型 | 範例 | 用途 |
|---|---|---|
| 計數器 (Counters) | 請求數、錯誤、失敗次數 | 趨勢、告警、負載 |
| 直方圖 (Histograms) | 回應時間、封包大小 | 值分布、百分位 |
| 量測表 (Gauge) | 記憶體使用、CPU | 資源當前狀態 |
| 總和 (Sum) | 資料總量、位元組 | 一段時間內的操作總量 |
範例:
- GET 請求的平均和 95 百分位回應時間。
- 當前線上使用者數。
- 記憶體使用 (Private Bytes, Working Set)。
- 500/503 類錯誤的發生頻率 (500/503)。
- 每分鐘的資料庫請求數。
這些指標不僅幫你找問題,還能幫你預防問題——例如伺服器負載升高或回應時間逐漸上升可能預示將來會有故障。
2. .NET 與 OpenTelemetry 指標蒐集架構
整體架構
在現代 .NET(從 .NET 6 起,特別是 .NET 8/9)有一套標準的指標蒐集系統,基於 OpenTelemetry。
運作流程如下:
- 應用程式程式碼 呼叫方法來增加 counters、註冊 gauges、記錄 histograms。
- OpenTelemetry Metrics SDK 在記憶體中蒐集這些指標,並定期送出。
- 指標匯出器 把指標傳到選定的監控系統(Prometheus、Application Insights、Grafana Cloud、Datadog 等)。
- 監控後端 聚合、儲存、視覺化,並建立告警與儀表板。
示意流程圖:
[你的應用程式]
⬇
[指標蒐集 (OpenTelemetry SDK)]
⬇
[指標匯出器 (Prometheus, AI, Datadog, ...)]
⬇
[監控系統/儀表板/告警]
3. 實作:在 C# 中使用指標的基礎
簡單的內部指標: System.Diagnostics.Metrics
.NET 提供內建的指標機制 — System.Diagnostics.Metrics。
主要角色: Meter, Counter<T>, Histogram<T>, ObservableGauge<T>。
範例:首頁訪問計數器
// 建立 Meter(通常整個應用只有一個)
using System.Diagnostics.Metrics;
static Meter meter = new Meter("MyCompany.MyApp", "1.0");
// 註冊計數器
static Counter<long> homePageVisits = meter.CreateCounter<long>("HomePageVisits");
// 在 controller 或 service 的某處...
public void HomePageRequested()
{
homePageVisits.Add(1);
// 其他頁面處理程式碼
}
註解:
- Meter 是用來產生指標的「工廠」,使用唯一名稱(應用/公司命名空間)。
- CreateCounter<long> 建立計數器;用 Add(1) 做遞增。
範例:測量回應時間
static Histogram<double> pageLoadTime = meter.CreateHistogram<double>("PageLoadTimeMs");
// 在請求處理器中:
public void OnRequest()
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// ...這裡是實際的請求處理...
stopwatch.Stop();
pageLoadTime.Record(stopwatch.Elapsed.TotalMilliseconds);
}
為動態值建立 Gauge
Gauge 是會隨時間變動的度量:線上使用者數、目前記憶體大小等。
static ObservableGauge<int> onlineUserGauge = meter.CreateObservableGauge(
"OnlineUsers",
() => GetOnlineUserCount());
// GetOnlineUserCount 是回傳即時值的方法
static int GetOnlineUserCount()
{
// 這裡放你實際的邏輯!
return ActiveUserList.Count;
}
在實務上這些都是非同步運作:應用程式報告指標值,匯出器去抓取它們(例如 Prometheus 會 scrape "/metrics" 端點)。
在現代 ASP.NET Core 應用中加入指標
對於 ASP.NET Core,很多東西開箱就支援。只要加上套件 OpenTelemetry.Instrumentation.AspNetCore,就會有 HTTP 請求、回應時間、錯誤數等指標。
在 Program.cs 的設定範例:
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MyApp"))
.AddAspNetCoreInstrumentation() // HTTP 指標
.AddRuntimeInstrumentation() // .NET CLR 的運行時指標
.AddProcessInstrumentation() // 程序的 CPU/記憶體
.AddMeter("MyCompany.MyApp") // 你的自訂指標來源
.AddPrometheusExporter(); // 匯出到 Prometheus
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
現在你的應用會在 /metrics 提供指標,Prometheus 或其他系統可以去 scrape。
4. 指標使用的實務範例
在真實專案中監控效能
連上指標來回答:
- API 的平均與峰值 RPS (requests per second) 是多少?
- 瓶頸在哪:一個 endpoint 是 300 ms,另一個是 2000 ms?
- 呼叫 DB 花了多少時間?(自訂 histograms)
範例:監控資料庫查詢時間
static Histogram<double> dbQueryDuration = meter.CreateHistogram<double>("DbQueryDurationMs");
public async Task<List<Product>> GetProductsAsync()
{
var sw = Stopwatch.StartNew();
var result = await _db.Products.ToListAsync();
sw.Stop();
dbQueryDuration.Record(sw.Elapsed.TotalMilliseconds);
return result;
}
範例:計算錯誤數
static Counter<long> apiErrors = meter.CreateCounter<long>("ApiErrors");
public IActionResult SomeEndpoint()
{
try
{
// 某些操作
return Ok();
}
catch (Exception)
{
apiErrors.Add(1);
throw;
}
}
使用 labels (tags) 來標註指標
把資料依有意義的維度分組很重要:endpoint、錯誤類型、使用者類型等。
homePageVisits.Add(
1,
KeyValuePair.Create<string, object>("UserType", "Admin"));
或者對直方圖:
dbQueryDuration.Record(
sw.Elapsed.TotalMilliseconds,
KeyValuePair.Create<string, object>("QueryType", "GetProducts"));
靠 tags 在 Grafana 就能做更細的切片分析,而不只看整個應用的總體數據。
5. 與 Prometheus、Application Insights、Datadog、Grafana 的整合
匯出器與整合
- Prometheus — 流行的 open-source 監控系統,已成為雲端與 Kubernetes 的事實標準。
- Application Insights — Azure 的雲端整合方案。
- Datadog, Grafana Cloud — 適合專業級基礎設施。
這些系統都可以透過 OpenTelemetry 的匯出器來接收 .NET 的指標。OTel 匯出器文件
Prometheus(步驟):
- 加入 NuGet 套件: OpenTelemetry.Exporter.Prometheus。
- 在指標註冊時加上 .AddPrometheusExporter()。
- 在 Grafana 設定 datasource 指向 Prometheus,並建立儀表板。
實用連結:
6. 特性、陷阱與常見錯誤
常見錯誤之一是 tags 過於細緻。如果給 tags 太多唯一值(例如使用者 ID 或訂單 ID),時序列 (time series) 數量會暴增 —— 這會造成指標儲存過載和成本上升(所謂的 cardinality explosion)。把 tags 維持在粗粒度。
有些開發者會忽視 System.Diagnostics.Metrics 與現成工具,自己用日誌和計時做「自造輪子」。結果是整合性差、維護麻煩。建議使用標準工具和自動化 instrumentations。
另一個錯誤是 指標有蒐集但沒有匯出。匯出器是必要的:例如加入 .AddPrometheusExporter(),並確認 /metrics 端點對 scrape 可用。
最後一點,別把指標類型搞混:平均回應時間不應只用 Counter 去計算,而是要用 Histogram —— 否則你看不到峰值與分布。Counters 用來計數;Histograms 用來時間/大小/分布;Gauges 用來當前狀態。
GO TO FULL VERSION