Выход ASP.NET Core 9 порадовал возможностью выборочно отключать http-метрики. В статье сценарии использования с примерами и детальный разбор того, как всё устроено под капотом.
Зачем нужны метрики
В отличие от логов, метрики не показывают детали какого-то конкретного единичного действия. Они дают общее представление текущего состояния сервиса. Например, можно посмотреть количество запросов к сервису или определённым endpoint-ам в единицу времени, а еще длительность выполнения запросов.
Зачем отключать метрики
Обычно у приложения есть технические endpoint-ы — например, health check или ручка скрейпинга метрик для сборщика. По этим endpoint-ам обычно никто не смотрит метрики. А при расчёте статистик они могут быть даже вредны. Для таких endpoint-ов полезно иметь инструмент с простым синтаксисом, который выборочно отключит сбор метрик.
Как отключать метрики
Отключение метрик в ASP.NET Core 9 работает для minimal API, контроллеров и middleware.
Minimal API
Тут всё просто. Для IEndpointConventionBuilder есть метод расширения DisableHttpMetrics. Его можно вызвать для любых endpoint-ов и групп, чтобы отключить сбор http-метрик:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry();
var app = builder.Build();
app.MapGet("/", () => "endpoint").DisableHttpMetrics();
var group = app.MapGroup("/group").DisableHttpMetrics();
app.MapHealthChecks("/healthz").DisableHttpMetrics();
app.Run();Под капотом тоже всё понятно. К метаданным endpoint-а добавляется атрибут DisableHttpMetricsAttribute. Он реализует интерфейс IDisableHttpMetricsMetadata.
Контроллеры
Тут всё ещё проще. DisableHttpMetrics можно добавить либо ко всему контроллеру, либо к его методам:
[ApiController]
[Route("")]
[DisableHttpMetrics]
public class CustomController : ControllerBase
{
[DisableHttpMetrics]
[HttpGet]
public string Get() => "Hello World!";
}Middleware
А вот тут всё интереснее. В middleware отключение метрик регулируется свойством MetricsDisabled объекта IHttpMetricsTagsFeature. И работает это не для указанного Endpoint-а, а для определённого условия. Это открывает большие возможности для гибкой настройки сбора http-метрик. Например, если запрос содержит какой-то специальный header, метрики не будут собираться независимо от маршрута:
internal partial class CustomMiddleware(RequestDelegate next)
{
public Task Invoke(HttpContext context)
{
var metricsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
if (metricsFeature != null &&
context.Request.Headers.ContainsKey("x-disable-metrics"))
{
metricsFeature.MetricsDisabled = true;
}
return next(context);
}
}Что под капотом
С отключением http-метрик всё прояснилось, но как именно это работает под капотом? Обычно для работы с метриками используются готовые библиотеки. Но если посмотреть в исходный код какого-нибудь популярного решения, например OpenTelemetry, там не будет ни одной проверки, связанной с DisableHttpMetricsAttribute, IDisableHttpMetricsMetadata или HttpMetricsTagsFeature.MetricsDisabled. Как тогда библиотека отслеживает, для каких запросов метрики собирать нужно, а для каких — нет?
А вот как. Начиная с восьмой версии, ASP.NET Core умеет в сбор основных метрик без подключения сторонних библиотек. А OpenTelemetry и аналогичные решения оперируют уже собранными данными. Соответственно, все проверки находятся в самом ASP.NET Core. Сначала в проверяется, есть ли у endpoint-а IDisableHttpMetricsMetadata и не выставлен ли флаг HttpMetricsTagsFeature.MetricsDisabled. Результат проверки передаётся в HostingMetrics.RequestEnd, где и прописана основная логика сбора или игнорирования метрик.
Итог
Минималистичный синтаксис делает инструмент простым и полезным
Можно назначить на конкретные маршруты. Либо для всех маршрутов, но при выполнении условий
Будет работать только для собственных метрик ASP.NET Core
Полезные ссылки
ASP.NET Core metrics | Learn
Introducing ASP.NET Core metrics and Grafana dashboards in .NET 8 | Devblogs
ASP.NET Core metrics | Overview
Add endpoint metadata to disable HTTP metrics | Issue
