Рубрики
Uncategorized

Метрики отчетности с использованием .NET (Core) Eventsource и EventCounter

Метрики отчетности с использованием .NET (Core) Eventsource и EventCounter. Помечено devops, csharp, мониторинг, ведение журнала.

Вряд ли кто-нибудь утверждает важность инструментария вашего кода и есть некоторые встроенные параметры журнала в .NET Framework, не говоря уже о бесчисленных больших 3-х сторонних библиотек, таких как nlog, serilog и log4net. Но когда дело доходит до метрики отчетности (подумайте: запросы в минуту, использование, скорость сообщений и тому подобное) встроенная поддержка очень ограничена. Конечно, у нас есть счетчики производительности, но их нельзя использовать кроссплатформу, так как они являются только Windows. К счастью, существует относительный простой способ сообщить метрики, используя класс Eventsource, который является кроссплатформой и частью структуры, поэтому нет необходимости в внешних зависимостях.

ETW (отслеживание событий для Windows) и События ...| класс уже давно был частью .NET Рамки. Регуляторы в значительной степени используются самими каркасом, а также многие (3-го вечеринка) библиотек. Это позволяет использовать структурированную регистрацию в своем приложении с минимальным накладным расходом производительности. Данные могут быть собраны в процессе или внепроцессу, используя такие инструменты, как Perfview Отказ

В этом сообщении мы посмотрим поближе к не так знакомую Счетчик событий Класс, который позволяет нам определять и сообщать метрики, используя События ...| Отказ Я специально хочу показать, как вы можете прочитать эти счетчики в процессе с использованием EventListener. Как это не очень хорошо Документировано Отказ

Как стартер, давайте посмотрим, что команда CoreFX должна сказать о Events Corters (взято из их Учебное пособие ):

Хотя Eventsource быстро, лесозаготавливайте слишком много событий для очень частых событий, по-прежнему является ударом производительности. В этом руководстве мы введем EventCounter, механизм измерения производительности для очень частых событий.

Для события, которое происходит очень часто (например, если это случится каждые несколько миллисекунд), в целом вы захотите накладные расходы на производительность на мероприятие (например, меньше, чем миллисекунда), в противном случае он будет стоить значительную производительность накладные расходы. Регистрация события, в конце дня, нужно что-то написать на диск. Если диск недостаточно быстро, вы потеряете события. Нам нужно решение, отличное от регистрации самого события.

При работе с большим количеством событий, зная мера на мероприятие, также не очень полезна. В большинстве случаев все, что нам нужно, это просто некоторые статистические данные. Таким образом, мы могли бы заставить статистику в самой процессе, а затем писать событие время от времени, чтобы сообщить о статистике, это то, что EventCounter будет для нас.

Звучит отлично, не так ли? Это вопрос определения и отчетности метрик, а рамки будут выполнять агрегацию и расчет в памяти. Все, что нам нужно сделать, это указать интервал, при котором данные выводятся.

Во-первых, нам нужно определить События ...| это будет содержать EventCounter экземпляры. Вы можете динамически создавать EventCounter экземпляры во время выполнения, но из-за ошибки я документировал здесь У вас будет создать хотя бы один EventCounter. экземпляр в конструкторе.

[EventSource(Name = "My-CustomMetricsEventSource-Minimal")]
public sealed class CustomMetricsEventSource : EventSource
{
    private EventCounter methodDurationCounter;

    private Dictionary dynamicCounters =
        new Dictionary();

    public static CustomMetricsEventSource Log = new CustomMetricsEventSource();

    public CustomMetricsEventSource()
    {
        methodDurationCounter = new EventCounter(nameof(methodDurationCounter), this);
    }

    public void ReportMethodDurationInMs(long milliseconds)
    {
        methodDurationCounter.WriteMetric(milliseconds);
    }

    public void ReportMetric(string name, float value)
    {
        if (!dynamicCounters.TryGetValue(name, out EventCounter counterInstance))
        {
            counterInstance = new EventCounter(name, this);
            dynamicCounters.Add(name, counterInstance);
        }
        counterInstance.WriteMetric(value);
    }
}

Мы будем использовать Custommetricseventsource Для регистрации наших метрик в консоли. Но нам также нужен слушатель, который поднимает зарегистрированные метрики и отправляет их в пункт назначения. В этом примере мы напишем данные в консоли, используя пользовательскую реализацию EventListener :

internal class CustomMetricsEventListener : EventListener
{
    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        var counterData = eventData.ToEventCounterData();

        // Only write to console if actual data has been reported
        if (counterData?.Count == 0)
            return;

        Console.WriteLine(
            $"Counter {counterData.Name} reported values " +
            $"Min: {counterData.Min}, " +
            $"Max: {counterData.Max}, " +
            $"Count {counterData.Count}, " +
            $"Mean {counterData.Mean}, " +
            $"StandardDeviation: {counterData.StandardDeviation}, " +
            $"IntervalSec: {counterData.IntervalSec}");
    }
}

Код, слушал выше, использует ТовентКустердата метод. Это на самом деле метод расширения. Возвращает EventCounterData Экземпляр, который облегчает работу с зарегистрированными метрическими данными:

public static class EventWrittenEventArgsExtensions
{
    public static bool IsEventCounter(this EventWrittenEventArgs eventData)
    {
        return eventData.EventName == "EventCounters";
    }

    public static EventCounterData ToEventCounterData(this EventWrittenEventArgs eventData)
    {
        if (!eventData.IsEventCounter())
            return null;

        return new EventCounterData(eventData);
    }
}

public class EventCounterData
{
    public EventCounterData(EventWrittenEventArgs eventData)
    {
        var payload = (IDictionary) eventData.Payload[0];

        Name = payload["Name"].ToString();
        Mean = (float)payload["Mean"];
        StandardDeviation = (float)payload["StandardDeviation"];
        Count = (int)payload["Count"];
        IntervalSec = (float)payload["IntervalSec"];
        Min = (float)payload["Min"];
        Max = (float)payload["Max"];
    }

    public string Name { get; }
    public float Mean { get; }
    public float StandardDeviation { get; }
    public int Count { get; }
    public float IntervalSec { get; }
    public float Min { get; }
    public float Max { get; }
}

Наконец, мы можем создать приложение консоли, которое позвонит Custommetricseventsource Для журнала метрических значений. CustomMetricseVentListener Построено таким образом, что метрики выводятся один раз в секунду.

Важно понимать, что это конфигурация CustomMetricseVentListener Это определяет метрический интервал отчетности. Это делается путем передачи числового значения, указав интервал в секундах к EventCounterIntervalsec аргумент

class Program
{
    static void Main(string[] args)
    {
        var reader = new CustomMetricsEventListener();
        var arguments = new Dictionary
        {
            {"EventCounterIntervalSec", "1"}
        };
        reader.EnableEvents(CustomMetricsEventSource.Log, EventLevel.LogAlways, EventKeywords.All, arguments);

        var random = new Random();
        for (int i = 0; i <= 10; i++)
        {
            SleepingBeauty(random.Next(10, 200));
        }

        Console.ReadKey();
    }

    static void SleepingBeauty(int sleepTimeInMs)
    {
        var stopwatch = Stopwatch.StartNew();

        Thread.Sleep(sleepTimeInMs);

        stopwatch.Stop();

        CustomMetricsEventSource.Log.ReportMethodDurationInMs(stopwatch.ElapsedMilliseconds);
        CustomMetricsEventSource.Log.ReportMetric("someCounter", DateTime.Now.Millisecond);
    }
}

Когда мы запустим программу, мы увидим, что метрические значения сообщаются на консоли:

Счетчик методика по методике.

Счетчик Somecounter Сообщенные значения Мин: 87, Макс.: 982, Count 9, Среднее 6031111, Стандартное представление: 269 2832, Интервалил: 1 026394

Делайте в голову, что метрики всегда будут сообщены по указанному интервалу (используя EventCounterterIntervalsec ) Даже если нет звонка WriteMetric Метод EventCounter экземпляр сделан. Все числовые значения, кроме Промежуток будет иметь значение по умолчанию 0.

Вы можете найти весь рабочий пример в моем репозитории GitHub:

Expecho/Blog.

Защитник для кода я вспомогал, видеть

Заполнитель для кода я вспомогал

Папки в этом репозитории

  • Метрики: отчетность метрики с использованием .NET (Основной)

Конечно, отчетность этих значений к консоли не добавляет большого значения, решать вам отправлять данные на вашу собственную Backenc. Вы могли бы, например, отправить их как пользовательские метрики для приложений Insights, используя EventCounterCollectionModule , войдите в свой стек ELK или любую систему журнала, которую вы используете.

Я действительно желаю, чтобы сообщить, что метрики получают немного больше внимания, поскольку имение данных на метрах очень важно для того, чтобы получить подробное понимание того, как ваше приложение ведет себя. Например, вы можете использовать метрики, чтобы масштабировать или выйти или получить идею в использовании определенных частей вашего приложения. Большинство структур лесозаготов, которые я знаю, не обслуживаете метрики.

Было много обсуждений о том, стоит ли метрика поддержки, используя новую Ilogger Интерфейс .NET. Ядро, но в конце концов нет поддержки для этого правильно знать. Подробнее о том, как и то почему можно прочитать в вопросе, созданной для этого обсуждения:

Обзор

Мы хотим включить приложения для излучения произвольных названных метрик, и у них есть их схватывание систем телеметрии/лесозаготовок (INPONT INSIGHT, ELASTICSearch/ELK и т. Д.), а также другие системы метрик (STATSD, INTOUXDB и т. Д.). Желается абстракция, чтобы позволить приложениям излучать метрики, не связанные с пунктом назначения метрик, особенно с такими функциями, как App Insights Auto-Lightup, в котором приложение не зависит от понимания приложений.

Предложение

Мы добавим поддержку отчетности метрик на Ilogger Отказ Это будет сделано через новый интерфейс компаньона Imetricslogger , какие регистраторы могут При желании воплощать в жизнь. Приложения могут выделять метрики через этот интерфейс (см. API ниже), а провайдеры регистратора, которые поддерживают метрики, могут получать и обрабатывать эти метрики. Метрики — это (имя, значение) кортежи, где ценность всегда с плавающей запятой номер. Ожидается, что метрики будут рассматриваться в совокупности, следовательно, не имеет смысла использовать универсальный тип данных, как объект Для метрики, поэтому метрические значения всегда Двойной с. Поддержка произвольных типов метрических значений является нецелевой. Метрики отчетности должны быть максимально эффективными, особенно в том случае, если для них не зарегистрировано поставщик регистратора регистратора, или они отфильтрованы.

Зачем Добавить в ilogger?

Первоначально я считал разработкой новой абстракции для метрик. Однако я столкнулся с несколькими проблемами:

  1. Нам нужно будет разработать структуру для именования/организации метрик (скорее всего, используя имена типа/пространства имен в качестве основы)
  2. Нам понадобится разработать структуру для фильтрации метрик (по категориям, имена, зернистам и т. Д.)
  3. Многие телеметрические системы обеспечивают поддержку как в журнале и метрической коллекции, и придется предоставить новую систему
  4. Потребители должны тянуть в две разные репортеры диагностики из ди ( ilogger , ImetricReporter и т. Д.)
  5. Это создало бы еще одну диагностику абстракции (на вершине событий, EventSounters, Diagnosticsource, Perf Cashers, Yada Yada Yada (см. Что я там делал? ;П))

Тот факт, что 1 и 2 выше, уже существуют в лесозаготовительном трубопроводе, и многие метрические раковины также регистрируют раковины, привели к идее интеграции метрик в ведение журнала, а не создание совершенно новой абстракции.

Основная причина, по которой мы бы …| не Хотите добавить это в Ilogger был бы риском

API.

Imetriclogger

Дополнительный интерфейс компаньона для Ilogger Реализации, чтобы указать их поддержку метрик. Ilogger Экземпляры, возвращенные IloggerProvider Ожидается, что будет реализовать этот интерфейс Если и только если Они хотят получать метрики.

namespace Microsoft.Extensions.Logging
{
    public interface IMetricLogger
    {
        /// 
        /// Define a new metric with the provided name and return an  that can be used to report values for that metric.
        /// 
        /// The name of the metric to define
        /// An  that can be used to report values for the metric
        IMetric DefineMetric(string name);
    }
}

Иминый

Интерфейс, который позволяет сообщать метрические данные. Метрические значения

namespace Microsoft.Extensions.Logging
{
    public interface IMetric
    {
        /// 
        /// Record a new value for this metric.
        /// 
        /// The value to record for this metric
        void RecordValue(double value);
    }
}

Loggermetricsextensions.

Предоставляет метод расширения на Ilogger Чтобы потребители позволили потребителям излучать метрики, даже если основной поставщик регистратора регистратора не поддерживает (, конечно, метрики будут игнорироваться в этом случае).

namespace Microsoft.Extensions.Logging
{
    public static class LoggerMetricsExtensions
    {
        /// 
        /// Define a new metric with the provided name and return an  that can be used to report values for that metric.
        /// 
        /// 
        /// If none of the registered logger providers support metrics, values recorded by this metric will be lost.
        /// 
        /// The name of the metric to define
        /// An  that can be used to report values for the metric
        public static IMetric DefineMetric(this ILogger logger, string name)
        {
            if(logger is IMetricLogger metricLogger)
            {
                return metricLogger.DefineMetric(name);
            }
            return NullMetric.Instance;
        }
    }
}

MetricValuextensions.

Методы расширения для Инометрический Чтобы поддержать другие общие типы метрики (как упомянуто выше, основной тип все еще Двойной Таким образом, значение должно быть представлено как Двойной ).

Предложение: мы могли бы иметь .Время () API, который возвращает ан. Idisposable который использует секундомер, чтобы сделать время для вас. Это было бы легко добавить позже.

using System;

namespace Microsoft.Extensions.Logging
{
    public static class MetricValueExtensions
    {
        /// 
        /// Record a new value for this metric.
        /// 
        /// 
        /// This is a convenience method that will convert the  to a  via
        /// the  property.
        /// 
        /// The metric to record the value on.
        /// The value to record for this metric.
        public static void RecordValue(this IMetric metric, TimeSpan value) => metric.RecordValue(value.TotalMilliseconds);
    }
}

Обновления регистратора

Совокупность Логин Класс, который мы возвращаем из Loggerfactory. Createlogger будет обновлен для поддержки Imetricslogger даже если ни один из Ilogger S, агрегаты поддерживают его. Он отправит бы метрики только к журналам, которые, как известно, поддерживают интерфейс.

Определить/запись

Для того, чтобы сохранить стоимость производительности как можно ниже для записи фактического метрического значения, API использует Определить / Запись шаблон. Потребители должны ожидать, чтобы позвонить Определенный ("Foo") Однажды Для определенного значения «Foo» и хранить результат как можно по всему миру (в типов Singleton и т. Д.). Это Определенный Это делает большую часть работы, чтобы создать метрическую запись. После звонка Определенный , RecordValue Позвоните на Инометрический Интерфейс может выбрать, как хранить значение, основанное на потребностях поставщиков. Например, в провайдере, который планирует отправить предварительно агрегированные метрики, RecordValue может просто обновить прокатные совокупные значения, а затем отбросить фактическую запись (таким образом, имеющие постоянные требования к хранению для каждой метрики). Если поставщик должен сообщить отдельных метрик, он может использовать динамически выделенные буферы или кольцевые буферы, в зависимости от конфигурации и потребностей провайдера. В качестве примера Инометрический Внедрение на основе предварительно агрегирующих данных, см. https://gist.github.com/anurse/03C6746204317BD3616C372B4DF9DBBA

Фильтрация метрик

Метрики должны быть фильтрующими, и они должны участвовать в существующем фильтрующем конвейере регистратора. Мое текущее предложение заключается в том, что метрики обрабатываются как LogLevel. Критический Сообщения, в этом, если категория вообще включена, метрики написаны. Мы могли бы рассмотреть возможность захвата Логика в .Definemetric и используя это для обеспечения разных «уровней» метрик. Поскольку существующие фильтры позволяют вам фильтровать поставщику, категорию и уровню, очень сложно отфильтровать конкретные метрики по имени (как это потребуется новая структура фильтра). Это может сделать Логика Поддержка метрик более важных.

@pakrym, и я разговаривал и придумал конкретное предложение

Метрики могут быть отфильтрованы у поставщика и названия категории, но нет концепции Loglevel для метрик. Тем не менее, фильтры могут отключить все Метрики для определенного комбинации поставщика/категории. Для этого мы добавим Autommetrics логический до Loggerfilterrule какие по умолчанию на правда Отказ При написании метрики мы проверим название провайдера и категории против параметров фильтра, а также проверяя этот логический.

Сумки и сумки имущества

Обратная связь запрашивается

Моя первоначальная мысль заключается в том, что метрики существуют за пределами принципов, поскольку они, как правило, агрегируются, и обзоры подразумевают данные для каждого события. Поставщики могли, в теории, дать своим Инометрический Экземпляры доступ к читанию активных данных охвата данных и прикрепите их к метрикам, если они выбирают (например, системы, которые сообщают о негагентных метриках, могут захотеть). По аналогичным причинам, сумки имущества (I.E. Значения журнала/структурированные ведения журнала и т. Д.) Не имеют смысла для метрик в целом, поскольку они обычно агрегируются. Сказав это, многие провайдеры поддерживают произвольные свойства (IncoluxDB, Incoms Insights), поэтому какой-то уровень поддержки может быть полезен. Мы могли бы легко добавить дополнительный параметр в .RecordValue Чтобы обеспечить добавление произвольных свойств каждому метрике, и провайдеры могли бы нерешить его, если это не имеет смысла для этого провайдера.

Влияние на существующие поставщики

Существуют минимальное влияние на существующие поставщики. Поскольку интерфейс предоставляет модель opt-in для провайдера для приема метрик, существующие поставщики не затронуты. Я полагаю, что провайдеры, такие как Serilog, не участвуют в этой системе, поскольку у них нет инфраструктуры для метрик (/CC @nblumhardt, я могу ошибаться!). Подобные провайдеры, такие как Incom Insights, могут выбрать либо добавлять поддержку метрик для своих существующих поставщиков, либо добавлять новые поставщики, которые обрабатывают только метрики (и игнорировать сообщения журнала), которые являются совместно зарегистрированы.

Оригинал: «https://dev.to/expecho/reporting-metrics-using-net-core-eventsource-and-eventcounter-23dn»