.NET 和 .NET Core 中的自訂計量集合

Azure 監視器 Application Insights .NET 和 .NET Core SDK 有兩種不同方法可收集自訂計量:TrackMetric()GetMetric()。 這兩種方法之間的主要差異是本機彙總。 TrackMetric() 方法缺少預先彙總。 GetMetric() 方法有預先彙總。 建議使用彙總,因此 TrackMetric() 不再是收集自訂計量的慣用方法。 此文章將逐步引導您使用 GetMetric() 方法,以及其運作方式背後的一些原理。

注意

下列文件以 Application Insights 傳統 API 為依據。 Application Insights 的長期計劃是使用 OpenTelemetry 收集資料。 如需詳細資訊,請參閱為 .NET、Node.js、Python 和 Java 應用程式啟用 Azure 監視器 OpenTelemetry

預先彙總與非預先彙總 API

TrackMetric() 方法會傳送代表計量的原始遙測。 針對每個值傳送單一遙測項目的效率不佳。 TrackMetric() 方法在效能方面的效率也不佳,因為每個 TrackMetric(item) 都要經過遙測初始設定式和處理器的完整 SDK 管線。

不同於 TrackMetric()GetMetric() 會為您處理本機預先彙總,然後只以一分鐘的固定間隔提交彙總的摘要計量。 如果您需要以秒或甚至毫秒層級密切監視某些自訂計量,您可以執行此動作,同時僅會產生每分鐘只監視一次的儲存體和網路流量成本。 此行為也可大幅降低發生節流的風險,因為需要針對彙總計量傳送的遙測項目總數會大幅降低。

在 Application Insights 中,透過 TrackMetric()GetMetric() 收集的自訂計量不會受到取樣影響。 針對重要計量進行取樣,可能導致警示您圍繞那些計量所建置的案例變得不可靠。 由於絕對不會針對您的自訂計量進行取樣,因此,您通常能夠確信當警示閾值有缺口時,就會引發警示。 因為不會針對自訂計量進行取樣,所以有一些潛在的疑慮。

逐秒追蹤計量中的趨勢,或使用更精細的間隔,可能會導致:

  • 增加資料儲存體成本。 傳送至 Azure 監視器的資料量會產生相關聯的成本。 您傳送的資料越多,整體監視成本就越高。
  • 增加網路流量或效能額外負荷。 在某些情況下,此額外負荷可能同時帶來費用與應用程式效能成本。
  • 擷取節流的風險。 您的應用程式在短時間內傳送高比率的遙測時,Azure 監視器就會捨棄 (「節流」) 資料點。

節流可能會導致警示闕漏,是一項顧慮。 觸發警示的條件可能會在本地發生,但隨後在擷取端點上可能因傳送的資料過多而遭到卸除。 除非您實作了自己的本機彙總邏輯,否則不建議對 .NET 和 .NET Core 使用 TrackMetric()。 如果您嘗試追蹤每個會在指定時段發生事件的執行個體,則可能發現 TrackEvent() 更適合。 請記住,與自訂計量不同,自訂事件需要進行取樣。 即使您未撰寫自己的本機預先彙總,仍然可以使用 TrackMetric()。 但是,如果您這麼做,請注意其缺陷。

總言之,建議使用 GetMetric(),因為它會執行預先彙總,所以會累積來自全部 Track() 呼叫的值,且每分鐘傳送摘要/彙總一次。 GetMetric() 方法可透過傳送較少資料點,同時仍能收集全部相關資訊,大幅降低成本和效能額外負荷。

注意

只有 .NET 和 .NET Core SDK 具有 GetMetric() 方法。 如果您使用 Java,請參閱使用 Micrometer 傳送自訂計量。 針對 JavaScript 和 Node.js,您仍可使用 TrackMetric(),但請記住上一節概述的注意事項。 針對 Python,您可以使用 OpenCensus.stats 來傳送自訂計量,但計量實作不同。

開始使用 GetMetric

在我們的範例中,將使用基本的 .NET Core 3.1 背景工作服務應用程式。 如果您想要複寫用於這些範例的測試環境,請遵循監視背景工作角色服務一文的步驟 1-6。 這些步驟會將 Application Insights 新增至基本背景工作角色服務專案範本。 這些概念適用於任何可使用 SDK 的一般應用程式,包括 Web 應用程式和主控台應用程式。

傳送計量

以下列程式碼取代 worker.cs 檔案的內容:

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.ApplicationInsights;

namespace WorkerService3
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private TelemetryClient _telemetryClient;

        public Worker(ILogger<Worker> logger, TelemetryClient tc)
        {
            _logger = logger;
            _telemetryClient = tc;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {   // The following line demonstrates usages of GetMetric API.
            // Here "computersSold", a custom metric name, is being tracked with a value of 42 every second.
            while (!stoppingToken.IsCancellationRequested)
            {
                _telemetryClient.GetMetric("ComputersSold").TrackValue(42);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

執行範例程式碼時,您會看到 while 迴圈重複執行,且 Visual Studio 輸出視窗中不會傳送任何遙測。 單一遙測項目會在 60 秒左右傳送,在我們的測試中顯示如下:

Application Insights Telemetry: {"name":"Microsoft.ApplicationInsights.Dev.00000000-0000-0000-0000-000000000000.Metric", "time":"2019-12-28T00:54:19.0000000Z",
"ikey":"00000000-0000-0000-0000-000000000000",
"tags":{"ai.application.ver":"1.0.0.0",
"ai.cloud.roleInstance":"Test-Computer-Name",
"ai.internal.sdkVersion":"m-agg2c:2.12.0-21496",
"ai.internal.nodeName":"Test-Computer-Name"},
"data":{"baseType":"MetricData",
"baseData":{"ver":2,"metrics":[{"name":"ComputersSold",
"kind":"Aggregation",
"value":1722,
"count":41,
"min":42,
"max":42,
"stdDev":0}],
"properties":{"_MS.AggregationIntervalMs":"42000",
"DeveloperMode":"true"}}}}

此單一遙測項目代表 41 個相異公制度量單位的彙總。 由於我們反覆傳送相同值,因此,我們的「標準差 (stDev))」為 0,且最大值 (max) 和最小值 (min) 的值完全相同。 value 屬性代表已彙總的全部個別值總和。

注意

GetMetric 不支援追蹤最後一個值 (例如,gauge) 或追蹤長條圖或分佈。

如果我們檢查 [記錄 (分析)] 體驗中的 Application Insights 資源,個別遙測項目下列螢幕擷取畫面所示。

Screenshot that shows the Log Analytics query view.

注意

儘管原始遙測項目並未在內嵌後包含明確的總和屬性/欄位,但我們會為您建立一個。 在此情況下,valuevalueSum 屬性都代表同一個項目。

您也可以在入口網站的 [計量] 區段中存取自訂計量遙測,做為記錄型和自訂計量。 下列螢幕擷取畫面是記錄型計量的範例。

Screenshot that shows the Metrics explorer view.

適用於高輸送量用途的快取計量參考

在某些情況下,可能會經常觀察到計量值。 例如,處理每秒 500 個要求的高輸送量服務,可能想要針對每個要求發出 20 個遙測計量。 此結果表示每秒會追蹤 10,000 個值。 在這類高輸送量案例中,使用者可能需要避免某些查閱來協助 SDK。

例如,上述範例對計量 ComputersSold 執行控制代碼的查閱,然後追蹤觀察到的值 42。 相反地,可能會快取多個追蹤叫用的控制代碼:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is where the cache is stored to handle faster lookup
            Metric computersSold = _telemetryClient.GetMetric("ComputersSold");
            while (!stoppingToken.IsCancellationRequested)
            {

                computersSold.TrackValue(42);

                computersSold.TrackValue(142);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

除了快取計量控制代碼之外,上述範例也將 Task.Delay 縮減為 50 毫秒,讓迴圈執行頻率更高。 結果產生 772 次 TrackValue() 叫用。

多維度計量

上一節的範例顯示零維度計量。 計量也可以是多維度的。 目前最多支援 10 個維度。

以下是如何建立一維計量的範例:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is an example of a metric with a single dimension.
            // FormFactor is the name of the dimension.
            Metric computersSold= _telemetryClient.GetMetric("ComputersSold", "FormFactor");

            while (!stoppingToken.IsCancellationRequested)
            {
                // The number of arguments (dimension values)
                // must match the number of dimensions specified while GetMetric.
                // Laptop, Tablet, etc are values for the dimension "FormFactor"
                computersSold.TrackValue(42, "Laptop");
                computersSold.TrackValue(20, "Tablet");
                computersSold.TrackValue(126, "Desktop");


                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

執行範例程式碼至少 60 秒會導致三個不同的遙測項目傳送至 Azure。 每個項目都代表三種尺寸之一的彙總。 和之前一樣,您可以在 [記錄 (分析)] 檢視中進一步檢查。

Screenshot that shows the Log Analytics view of multidimensional metric.

在計量瀏覽器中:

Screenshot that shows Custom metrics.

請注意,您無法依新的自訂維度分割計量,或使用計量檢視來檢視自訂維度。

Screenshot that shows splitting support.

根據預設,不會在 Application Insights 資源中開啟計量瀏覽器中的多維度計量。

啟用多維度計量

若要為 Application Insights 資源啟用多維度計量,請選取 [使用量和估計成本]>[自訂計量]>[啟用自訂計量維度的警示]>[確定]。 如需詳細資訊,請參閱自訂計量維度和預先彙總

在您進行該變更並傳送新的多維度遙測之後,您可以選取 [套用分割]

注意

只有在入口網站中開啟該功能之後新傳送的計量才會儲存維度。

Screenshot that shows applying splitting.

檢視每個 FormFactor 維度的計量彙總。

Screenshot that shows form factors.

在有三個以上的維度時使用 MetricIdentifier

目前支援 10 個維度。 超過 3 個維度需要使用 MetricIdentifier

// Add "using Microsoft.ApplicationInsights.Metrics;" to use MetricIdentifier
// MetricIdentifier id = new MetricIdentifier("[metricNamespace]","[metricId],"[dim1]","[dim2]","[dim3]","[dim4]","[dim5]");
MetricIdentifier id = new MetricIdentifier("CustomMetricNamespace","ComputerSold", "FormFactor", "GraphicsCard", "MemorySpeed", "BatteryCapacity", "StorageCapacity");
Metric computersSold  = _telemetryClient.GetMetric(id);
computersSold.TrackValue(110,"Laptop", "Nvidia", "DDR4", "39Wh", "1TB");

自訂計量設定

如果您想要更改計量設定,就必須在計量進行初始化的位置執行更改。

特殊維度名稱

計量不會使用用來存取這些計量的 TelemetryClient 之中的遙測內容。 使用 MetricDimensionNames 類別中做為常數的特殊維度名稱是這項限制的最佳因應措施。

下列 Special Operation Request Size 計量所傳送的計量 總不會Context.Operation.Name 設定為 Special OperationTrackMetric() 方法或其他任何 TrackXXX() 方法會將 OperationName 正確設定為 Special Operation

        //...
        TelemetryClient specialClient;
        private static int GetCurrentRequestSize()
        {
            // Do stuff
            return 1100;
        }
        int requestSize = GetCurrentRequestSize()

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                //...
                specialClient.Context.Operation.Name = "Special Operation";
                specialClient.GetMetric("Special Operation Request Size").TrackValue(requestSize);
                //...
            }
                   
        }

在此情況下,請使用 MetricDimensionNames 類別中所列的特殊維度名稱來指定 TelemetryContext 值。

例如,在將下一個陳述式所產生的計量彙總傳送到 Application Insights 雲端端點時,其中的 Context.Operation.Name 資料欄位將設定為 Special Operation

_telemetryClient.GetMetric("Request Size", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation");

此特殊維度的值將複製到 TelemetryContext,而且不會當做「正常」維度使用。 如果您想要讓作業維度保持正常計量探索,則必須基於該目的建立個別維度:

_telemetryClient.GetMetric("Request Size", "Operation Name", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation", "Special Operation");

維度和時間序列上限

若要防止遙測子系統意外使用您的資源,您可以控制每個計量的資料數列數目上限。 預設限制為每個計量不超過 1000 個資料數列總數,而且每個維度不超過 100 個不同值。

重要

請對維度使用低基數值,以避免節流。

在維度和時間序列上限的內容中,我們使用 Metric.TrackValue(..) 來確保會觀察到限制。 如果已達到限制,Metric.TrackValue(..) 將傳回 False 且不會追蹤值。 否則會傳回 True。 如果計量的資料源自使用者輸入,此行為將有其效用。

MetricConfiguration 建構函式採用一些選項,說明如何在個別計量內管理不同數列,以及實作 IMetricSeriesConfiguration 的類別物件,以指定計量每個個別數列的彙總行為:

var metConfig = new MetricConfiguration(seriesCountLimit: 100, valuesPerDimensionLimit:2,
                new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false));

Metric computersSold = _telemetryClient.GetMetric("ComputersSold", "Dimension1", "Dimension2", metConfig);

// Start tracking.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value1");
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value2");

// The following call gives 3rd unique value for dimension2, which is above the limit of 2.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3");
// The above call does not track the metric, and returns false.
  • seriesCountLimit 是計量可包含的資料時間序列數目上限。 達到此限制時,對 TrackValue() 的呼叫通常會導致新序列傳回 false
  • valuesPerDimensionLimit 會以類似方式來限制每個維度的相異值數目。
  • restrictToUInt32Values 會判斷是否應該追蹤非負整數值。

以下範例說明如何傳送訊息,以了解是否已超過上限限制:

if (! computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3"))
{
// Add "using Microsoft.ApplicationInsights.DataContract;" to use SeverityLevel.Error
_telemetryClient.TrackTrace("Metric value not tracked as value of one of the dimension exceeded the cap. Revisit the dimensions to ensure they are within the limits",
SeverityLevel.Error);
}

下一步