Метрики в 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 шт):
Как уже было сказано в самом вопросе - я все же использовал библиотеку 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
У него есть свои недостатки, но это хороший шаблон для теста так как большинство его графиков сразу будут работать и вы узнаете, что все получилось.
Вот небольшой кусочек:

Если данных нет - идем по порядку:
Ставим фидлер, в стартапе меняем вот эту строчку:
options.InfluxDb.BaseUri = new Uri("http://localhost:8186");на вот эту:
options.InfluxDb.BaseUri = new Uri("http://localhost.fiddler:8186");
Не забываем, что у вас может быть другой порт. Запускаем приложение, открываем фидлер и смотрим отправляет ли он данные в телеграф. Если все ок:
- Ставим Сhronograf: https://docs.influxdata.com/chronograf/v1.8/ Это довольно простая утилитка, которая может подключится к вашей InfluxDB и показать, что у вас туда прилетело. Если данных нет - смотрите на output-плагин телеграфа, а если данные есть - смотрите на источник данных в графане.