Поделиться через


Сбор пользовательских метрик в .NET и .NET Core

Пакеты SDK для Azure Monitor Application Insights для .NET и .NET Core имеют два разных метода сбора пользовательских метрик: TrackMetric() и GetMetric(). Основное различие между этими двумя методами заключается в локальном агрегировании. Метод TrackMetric() не имеет предварительной статистической обработки. Метод GetMetric() имеет предварительную агрегацию. Рекомендуется использовать агрегирование, поэтому TrackMetric() больше не является предпочтительным методом сбора пользовательских метрик. В этой статье описывается использование GetMetric() метода и некоторые из причин его работы.

Примечание.

В следующей документации используется классический API Application Insights. Долгосрочный план Application Insights — сбор данных с помощью OpenTelemetry. Дополнительные сведения см. в статье "Включение Azure Monitor OpenTelemetry для .NET", Node.js, приложений Python и Java и нашей стратегии OpenTelemetry. Рекомендации по миграции доступны для .NET, Node.js и Python.

Предварительная агрегирование и api без предварительной подготовки

Метод TrackMetric() отправляет необработанные данные телеметрии, обозначающие метрику. Отправка одного элемента телеметрии для каждого значения является неэффективной. Метод TrackMetric() также неэффективн в плане производительности, так как каждый TrackMetric(item) проходит через полный конвейер пакета SDK для инициализаторов телеметрии и процессоров.

В отличие TrackMetric()от этого, GetMetric() обрабатывает локальную предварительную агрегацию, а затем отправляет только агрегированную сводную метрику с фиксированным интервалом в одну минуту. Если необходимо внимательно отслеживать некоторые пользовательские метрики на втором или даже миллисекундном уровне, это можно сделать, только в то время как влечет за собой только затраты на хранение и сетевой трафик только для мониторинга каждую минуту. Это также значительно снижает риск возникновения регулирования, поскольку общее количество элементов телеметрии, которые необходимо отправить для агрегированной метрики, значительно уменьшается.

В Application Insights пользовательские метрики, собранные с помощью TrackMetric() и GetMetric(), не подлежат выборке. Важные метрики выборки могут привести к сценариям, когда оповещения, которые могут быть созданы вокруг этих метрик, могут стать ненадежными. Никогда не выполняя выборку пользовательских метрик, вы можете быть уверены, что при нарушении пороговых значений оповещений оповещение возникает. Так как пользовательские метрики не выборки, существуют некоторые потенциальные проблемы.

Отслеживание трендов в метрике каждые секунды или на еще более детализированном интервале может привести к следующему:

  • Увеличение затрат на хранение данных. Увеличение объема данных, отправляемых в Azure Monitor, связано с большими затратами. Чем больше данных вы отправляете, тем больше общей стоимости мониторинга.
  • Увеличение нагрузки на сетевой трафик или производительность. В некоторых сценариях эта нагрузка может иметь как денежные, так и затраты на производительность приложений.
  • Риск регулирования приема данных. Azure Monitor удаляет точки данных ("регулирование"), когда приложение отправляет высокую скорость телеметрии в короткий интервал времени.

Регулирование может привести к пропуску оповещений. Условие для активации оповещения может происходить локально, а затем удаляться в конечной точке приема из-за слишком большого объема отправленных данных. Мы не рекомендуем использовать TrackMetric() для .NET и .NET Core, если вы не реализовали собственную логику локального агрегирования. Если вы пытаетесь отслеживать каждый экземпляр события в течение заданного периода времени, вы можете найти, что TrackEvent() лучше. Однако следует помнить, что в отличие от пользовательских метрик, пользовательские события подлежат выборке. Вы по-прежнему можете использовать TrackMetric() даже без написания собственной локальной предварительной обработки. Но если вы это делаете, помните о ловушках.

В сводке рекомендуется GetMetric() , так как она выполняет предварительную агрегирование, она накапливает значения из всех Track() вызовов и отправляет сводку или агрегат каждые минуты. Метод GetMetric() может значительно сократить затраты и производительность, отправив меньше точек данных, а также собирая все соответствующие сведения.

Примечание.

Только пакеты SDK для .NET и .NET Core имеют GetMetric() метод. Если вы используете Java, см. статью "Отправка пользовательских метрик с помощью микрометра". Для JavaScript и Node.js вы по-прежнему используете TrackMetric(), но помните о предостережениях, описанных в предыдущем разделе. Для Python можно использовать OpenCensus.stats для отправки пользовательских метрик, но реализация метрик отличается.

Начало работы с GetMetric

В нашем примере мы будем использовать базовое приложение службы рабочей роли .NET Core 3.1. Если вы хотите реплицировать тестовую среду, используемую с этими примерами, выполните действия 1–6 в статье службы мониторинга рабочей роли. Эти действия добавляют Application Insights в базовый шаблон проекта рабочей службы. Основные понятия применяются к любому общему приложению, в котором можно использовать пакет SDK, включая веб-приложения и консольные приложения.

Отправка метрики

Замените содержимое файла 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 отдельного метрического измерения. Так как мы отправляли одно и то же значение снова и снова, у нас есть стандартное отклонение () с идентичными максимальными (stDevmax) 0 и минимальными (min) значениями. Свойство value представляет сумму всех отдельных значений, которые были агрегированы.

Примечание.

Метод GetMetric не поддерживает отслеживание последнего значения (например, gauge) или отслеживания гистограмм или распределения.

Если мы рассмотрим ресурс Application Insights в интерфейсе Logs (Analytics), отдельный элемент телеметрии будет выглядеть на следующем снимке экрана.

Снимок экрана: представление запроса Log Analytics.

Примечание.

Хотя необработанный элемент телеметрии не содержал явное свойство или поле суммы после приема, мы создадим его для вас. В этом случае как свойство, так value и valueSum свойство представляют то же самое.

Вы также можете получить доступ к пользовательской телеметрии метрик в разделе "Метрики" портала как на основе журнала, так и на основе пользовательской метрики. На следующем снимка экрана показан пример метрики на основе журнала.

Снимок экрана: представление обозревателя метрик.

Справочник по метрике кэша для использования высокой пропускной способности

Значения метрик часто могут наблюдаться в некоторых случаях. Например, служба высокой пропускной способности, обрабатывающая 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 трех отдельных элементов телеметрии. Каждый элемент представляет агрегат одного из трех форм-факторов. Как и раньше, вы можете продолжить изучение в представлении Журналов (Аналитика).

Снимок экрана: представление Log Analytics многомерной метрики.

В обозревателе метрик:

Снимок экрана: пользовательские метрики.

Обратите внимание, что вы не можете разделить метрику по новому пользовательскому измерению или просмотреть пользовательское измерение с помощью представления метрик.

Снимок экрана: поддержка разделения.

По умолчанию многомерные метрики в обозревателе метрик не включаются в ресурсы Application Insights.

Включение многомерных метрик

Чтобы включить многомерные метрики для ресурса Application Insights, выберите "Использование" и "Предполагаемые затраты>", чтобы включить оповещения о пользовательских измерениях>>метрик ОК. Дополнительные сведения см. в разделе "Пользовательские измерения метрик" и предварительной статистической обработки.

После внесения этого изменения и отправки новых многомерных данных телеметрии можно выбрать "Применить разделение".

Примечание.

Только вновь отправленные метрики после включения этой функции на портале будут иметь сохраненные измерения.

Снимок экрана: применение разделения.

Просмотрите агрегаты метрик для каждого FormFactor измерения.

Снимок экрана: форм-факторы.

Использование MetricIdentifier при наличии более трех измерений

В настоящее время поддерживаются 10 измерений. Для использования более трех измерений требуется: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 Operation. Метод TrackMetric() или любой другой 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);
}

Следующие шаги