Метрики в ASP.NET Core 3.1. Чем собирать внутри и чем их забирать?

Всем привет!

Превью: Я новичок в теме сбора метрик, как в .NET Framework так и в Core. Каждый день узнаю что-то новое, но мозги уже через ушы вытекают, так что очень надеюсь на помощь комьюнити.

О системе: ASP.NET Core приложение крутится на железном сервере под управлением Windows. Естественно - хостится на IIS. Здесь же (как и на многих других серверах) крутятся ASP.NET (не кор) приложения и виндовые сервисы, которые складируют свои метрики (в том числе кастомные) в Windows Performance Counters, а оттуда их забирает Zabbex агент и Telegraf агент. Для хранения собранных метрик InfluxDB. Рисует Графана.

Задача 1: подружить ASP.NET Core с Windows Performance Counters (далее WPC). Это вообще возможно?

Задача 2: если это не возможно - нужен самый надежный способ позволяющий собирать метрики и сохранять их перед отправкой в InfluxDB даже если на каком-то шаге что-то пошло не так (к примеру - сетевые проблемы, упал сервер с InfluxDB и т.д.). Желательно, что бы в этом участвовал Zabbex или Telegraf агент.

Prometeus-сервер не вариант так как никто не хочет разворачивать еще один сервис, когда есть телеграф и InfluxDB, но возможность использовать Prometeus-клиент не исключается так как телеграф умеет его вычитывать.

На данный момент пытаюсь понять возможно ли подружить App Metrics (https://www.app-metrics.io) с телеграфом, но пока что безуспешно так как поддержка ASP.NET Core 3.0+ еще не заимплеменчена полностью в этой библиотеке и половина функционала тупо отказывается работать (библиотека 4.0 в превью и никакой документации еще нет). Более того - так и не решен вопрос, что делать с метриками если телеграф по какой-то причине не может их забрать (здесь в случае Framework-a помогал WPC, который хранит метрики и агенты могут подобрать их в любой момент).

App Metrics умеет в файл писать (пока что не умеет и я пока не понял - дело в моих кривых руках или в том, что библиотека еще не готова, но файл не создается и никаких ошибок) и вот интересно, может ли телеграф из файла вычитывать метрики (не нашел пока ответа). Но даже если может - что делать с этим файлом после прочтения? Если мы все время будем в файл писать - он быстро вырастет до огромных размеров, а если мы включаем мод перезаписи (AppendMetricsToTextFile = false;) - мы не решаем проблему сохранения метрик, если их сейчас некому забрать.

Возможно вы знаете, как подружить другую библиотеку с телеграфом?

С удовольствием почитаю о ваших решениях и буду благодарен за любые предложения.

Ап: Последний прогресс с App Metrics - удалось открыть ендпоинт https://{my-site}/metrics (возвращает метрики в JSON) и https://{my-site}/metrics-text (возвращает метрики в отформатированном текстовом виде). https://{my-site}/env все еще не работает. Это не решает проблему с хранением метрик при не работающих агентах, но уже кое-что. Пойду смотреть телеграф. Возможно агент может накапливать метрики у себя, пока не отправит.

Ап:Нашел конфиги телеграфа, которые позволяют вычитывать метрики Prometeus и других клиентов. Теперь ищу аналогичные конфиги для Zabbix агента. Когда все будет готово - выложу подробности в ответе.

Ап: В конфиге Zabbix агента есть UserParameter следующего формата: UserParameter=<ключ>,<powershell команда/скрипт>, который дает возможность забирать данные к примеру через http запрос на наш эндпоинт /metrics, но вот дилемма. Не очень хочу использовать app-metrics так как он еще толком не готов для ASP.NET Core 3+, а аутпут прометеуса - это тупо текст. Кто-то знает, как перевести аутпут прометеуса в JSON, что бы распарсить его паввершел скриптом и вернуть из скрипта в zabbix корректно отформатированную строку?


Ответы (1 шт):

Автор решения: Dmytro

Как уже было сказано в самом вопросе - я все же использовал библиотеку App Metrics (https://www.app-metrics.io). А именно - следующие пакеты (самые актуальные на данный момент):

Install-Package App.Metrics -Version 4.0.0-preview1.0.7
Install-Package App.Metrics.AspNetCore 4.0.0-preview1.0.7
Install-Package App.Metrics.AspNetCore.Endpoints 4.0.0-preview1.0.7
Install-Package App.Metrics.AspNetCore.Mvc 4.0.0-preview1.0.7
Install-Package App.Metrics.AspNetCore.Tracking 4.0.0-preview1.0.7
Install-Package App.Metrics.Extensions.Configuration 4.0.0-preview1.0.7
Install-Package App.Metrics.Extensions.Hosting 4.0.0-preview1.0.7
Install-Package App.Metrics.Formatters.InfluxDB 4.0.0-preview1.0.7
Install-Package App.Metrics.Reporting.InfluxDB 4.0.0-preview1.0.7

У данной превью версии пакетов все работает стабильно. На данный момент багов не выявлено. Решил пока использовать без хелсчеков, а только для метрик. Zabbix использую как в последнем коменте Ап-е к вопросу.

Telegraf-агент использую как прокси. Телеграф может накапливать собранные метрики и отправлять их с задержкой, так что при сетевых проблемах или недоступности БД - он будет кэшировать метрики.

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

Program.sc:

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseInfluxDbReporter()
            .UseMetrics()
            .UseMetricsEndpoints()
            .UseMetricsWebTracking()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

private static IHostBuilder UseInfluxDbReporter(this IHostBuilder hostBuilder)
{
    var filter = new MetricsFilter();
    filter.WhereContext(c => c == MetricsRegistry.Context);
    hostBuilder.ConfigureMetricsWithDefaults(builder =>
    {
        builder.Filter.With(filter);
        builder.Report.ToInfluxDb(options =>
        {
            // адрес Telegraf-агента
            options.InfluxDb.BaseUri = new Uri("http://localhost:8186"); 
            options.InfluxDb.Database = "appmetricsdb";
            options.InfluxDb.Consistenency = "any";
            options.InfluxDb.UserName = "admin";
            options.InfluxDb.Password = "Password";
            options.InfluxDb.RetentionPolicy = "autogen";
            options.InfluxDb.CreateDataBaseIfNotExists = true;
            options.HttpPolicy.BackoffPeriod = TimeSpan.FromSeconds(30);
            options.HttpPolicy.FailuresBeforeBackoff = 5;
            options.HttpPolicy.Timeout = TimeSpan.FromSeconds(10);
            options.MetricsOutputFormatter = 
                     new MetricsInfluxDbLineProtocolOutputFormatter();
            options.Filter = filter;
            options.FlushInterval = TimeSpan.FromSeconds(1);
        });
    });
    return hostBuilder;
}

Startup.cs:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    var metrics = new MetricsBuilder()             
        .Configuration.ReadFrom(Configuration)
        .Configuration.Configure(options =>
        {
            // Пишу все метрики в один контекст, но вы можете не добавлять это поле
            // В таком случае - в "Application.HttpRequests" 
            // будут записаны метрики по умолчанию
            // а в ваши в контекст, который вы укажете в appsettings.json
            options.DefaultContextLabel = "Application.HttpRequests";
        })
        .OutputMetrics.AsInfluxDbLineProtocol()
        .Build();
    services.AddMetricsTrackingMiddleware(Configuration);
    services.AddMetricsEndpoints(Configuration);
    services.AddMetricsReportingHostedService();
    services.AddMetricsAuthorization();
    // configure sending scheduler:
    UseReporterScheduler(metrics);
    services.AddMetrics(metrics);
    services.AddControllers().AddMetrics(); 
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMetricsAllMiddleware();
    app.UseMetricsAllEndpoints();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

private static void UseReporterScheduler(IMetricsRoot metrics, int schedulerInterval = 5)
{
    var scheduler = new AppMetricsTaskScheduler(TimeSpan.FromSeconds(schedulerInterval),
        () =>
        {
            return Task.WhenAll(metrics.ReportRunner.RunAllAsync());

        });
    scheduler.Start();
}

appsettings.json:

"MetricsOptions": {
      "Enabled": true,
      "ReportingEnabled": true
    },
    "MetricsWebTrackingOptions": {
      "ApdexTrackingEnabled": true,
      "ApdexTSeconds": 0.1,
      "IgnoredHttpStatusCodes": [ 404 ],
      "IgnoredRoutesRegexPatterns": [],
      "OAuth2TrackingEnabled": false
    },
    "MetricEndpointsOptions": {
      "MetricsEndpointEnabled": true,
      "MetricsTextEndpointEnabled": true,
      "EnvironmentInfoEndpointEnabled": true
    }

Далее вы так же можете использовать различные метрики для замеров отдельных операций, но для начал советую собрать такой проект, запустить его, сделать пару запросов (желательно, что бы среди них были и не успешные) и открыть адрес https://localhost:port/metrics Возможно собранных метрик в вашем случае будет достаточно.

Конфиг input-плагина Telegraf-агента:

# # Influx HTTP write listener
[[inputs.http_listener]]
  ## Address and port to host HTTP listener on
  service_address = ":8186"

  ## timeouts
  read_timeout = "10s"
  write_timeout = "10s"

  ## HTTPS
  #tls_cert= "/etc/telegraf/cert.pem"
  #tls_key = "/etc/telegraf/key.pem"  

  ## MTLS
  #tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"]

  ## Basic authentication
  #basic_username = "foobar"
  #basic_password = "barfoo"

Данный конфиг позволит ловить запросы от вашего приложений, а уже в аутпут плагине вы укажите, куда хотите переслать данные. У меня там все по умолчанию, кроме адреса сервера, так что это не интересно.

Далее, что бы визуализировать данные я использовал следующий шаблон графаны: https://grafana.com/grafana/dashboards/2125

У него есть свои недостатки, но это хороший шаблон для теста так как большинство его графиков сразу будут работать и вы узнаете, что все получилось. Вот небольшой кусочек: введите сюда описание изображения

Если данных нет - идем по порядку:

  1. Ставим фидлер, в стартапе меняем вот эту строчку:

    options.InfluxDb.BaseUri = new Uri("http://localhost:8186");

    на вот эту:

    options.InfluxDb.BaseUri = new Uri("http://localhost.fiddler:8186");

Не забываем, что у вас может быть другой порт. Запускаем приложение, открываем фидлер и смотрим отправляет ли он данные в телеграф. Если все ок:

  1. Ставим Сhronograf: https://docs.influxdata.com/chronograf/v1.8/ Это довольно простая утилитка, которая может подключится к вашей InfluxDB и показать, что у вас туда прилетело. Если данных нет - смотрите на output-плагин телеграфа, а если данные есть - смотрите на источник данных в графане.
→ Ссылка