Métricas de ASP.NET Core

Las métricas son medidas numéricas que se comunican a lo largo del tiempo. Úselas para supervisar el estado de una aplicación y generar alertas. Por ejemplo, un servicio web podría realizar un seguimiento de:

  • Solicitudes que recibe por segundo.
  • Milisegundos necesarios para responder.
  • Respuestas que envía con error.

Informe de estas métricas a un sistema de supervisión a intervalos regulares. Configure paneles para ver las métricas y crear alertas para notificar a los usuarios de problemas. Si el servicio web está pensado para responder a solicitudes en un plazo de 400 ms y comienza a responder en 600 ms, el sistema de supervisión puede notificar al personal de operaciones que la respuesta de la aplicación es más lenta de lo normal.

La lista completa de todos los instrumentos junto con sus atributos se describe en ASP.NET Core métricas integradas.

Usar métricas

El uso de métricas implica lo siguiente:

  • Instrumentación: el código de las bibliotecas .NET toma medidas y las asocia a un nombre de métrica. .NET y ASP.NET Core incluyen muchas métricas integradas.
  • Colección y almacenamiento: una aplicaciones .NET configura métricas con nombre para que se transmitan desde la aplicación para el almacenamiento y el análisis externos. Algunas herramientas pueden realizar la configuración fuera de la aplicación mediante archivos de configuración o una herramienta de interfaz de usuario.
  • Visualización: Una herramienta que puede mostrar las métricas en un formato legible por humanos. Por ejemplo, Grafana y Prometheus.
  • Alertas: Una herramienta que proporciona notificaciones cuando una métrica supera un umbral. Por ejemplo, si el tiempo medio de respuesta de un servicio web supera los 400 ms, se puede enviar una alerta al personal de operaciones.
  • Análisis: Una herramienta que puede analizar las métricas a lo largo del tiempo. Esta herramienta suele ser un panel basado en web que se puede personalizar para mostrar las métricas más importantes de una aplicación específica.

El código instrumentado puede registrar medidas numéricas, pero para crear métricas útiles para la supervisión, debe agregar, transmitir y almacenar las medidas. Este proceso de agregación, transmisión y almacenamiento de los datos se denomina "colección". Este tutorial muestra varios ejemplos de recopilación y visualización de métricas:

También puede asociar medidas con pares clave-valor denominados etiquetas que permiten clasificar los datos para su análisis. Para obtener más información, consulte Métricas con múltiples dimensiones.

Crear la aplicación de inicio

Crear una aplicación ASP.NET Core con el siguiente comando:

dotnet new web -o WebMetric
cd WebMetric
dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore --prerelease
dotnet add package OpenTelemetry.Extensions.Hosting

Reemplace el contenido de Program.cs por el código siguiente:

using OpenTelemetry.Metrics;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
    .WithMetrics(builder =>
    {
        builder.AddPrometheusExporter();

        builder.AddMeter("Microsoft.AspNetCore.Hosting",
                         "Microsoft.AspNetCore.Server.Kestrel");
        builder.AddView("http.server.request.duration",
            new ExplicitBucketHistogramConfiguration
            {
                Boundaries = new double[] { 0, 0.005, 0.01, 0.025, 0.05,
                       0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10 }
            });
    });
var app = builder.Build();

app.MapPrometheusScrapingEndpoint();

app.MapGet("/", () => "Hello OpenTelemetry! ticks:"
                     + DateTime.Now.Ticks.ToString()[^3..]);

app.Run();

Visualización de métricas con dotnet-counters

dotnet-counters es una herramienta de línea de comandos que puede ver métricas dinámicas para aplicaciones .NET a petición. No requiere ninguna configuración, lo que la hace útil para investigaciones ad hoc o para comprobar que la instrumentación de métricas funciona. Funciona tanto con API basadas en System.Diagnostics.Metrics como con EventCounters.

Si la herramienta dotnet-counters no está instalada, ejecute el siguiente comando:

dotnet tool update -g dotnet-counters

Mientras se ejecuta la aplicación de prueba, inicie dotnet-counters. El comando siguiente muestra un ejemplo de cómo dotnet-counters supervisa todas las métricas del medidor de Microsoft.AspNetCore.Hosting.

dotnet-counters monitor -n WebMetric --counters Microsoft.AspNetCore.Hosting

Esto genera una salida similar a la siguiente:

Press p to pause, r to resume, q to quit.
    Status: Running

[Microsoft.AspNetCore.Hosting]
    http-server-current-requests
        host=localhost,method=GET,port=5045,scheme=http                    0
    http-server-request-duration (s)
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0.001
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0.001
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0.001
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0
        host=localhost,method=GET,port=5045,protocol=HTTP/1.1,ro           0

Para obtener más información, vea dotnet-counters.

Enriquecer la métrica de solicitud de ASP.NET Core

ASP.NET Core tiene muchas métricas integradas. La métrica http.server.request.duration:

  • Registra la duración de las solicitudes HTTP en el servidor.
  • Captura la información de solicitud en etiquetas, como el código de estado de respuesta y la ruta coincidente.

La http.server.request.duration métrica admite el enriquecimiento de etiquetas mediante IHttpMetricsTagsFeature. El enriquecimiento se produce cuando una biblioteca o aplicación agrega sus propias etiquetas a una métrica. Esta característica es útil si una aplicación quiere agregar una categorización personalizada a paneles o alertas compiladas con métricas.

using Microsoft.AspNetCore.Http.Features;

var builder = WebApplication.CreateBuilder();
var app = builder.Build();

app.Use(async (context, next) =>
{
    var tagsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
    if (tagsFeature != null)
    {
        var source = context.Request.Query["utm_medium"].ToString() switch
        {
            "" => "none",
            "social" => "social",
            "email" => "email",
            "organic" => "organic",
            _ => "other"
        };
        tagsFeature.Tags.Add(new KeyValuePair<string, object?>("mkt_medium", source));
    }

    await next.Invoke();
});

app.MapGet("/", () => "Hello World!");

app.Run();

Ejemplo anterior:

  • Agrega middleware para enriquecer la métrica de solicitud de ASP.NET Core.
  • Obtiene el elemento IHttpMetricsTagsFeature desde HttpContext. La característica solo está presente en el contexto si alguien escucha la métrica. Compruebe que IHttpMetricsTagsFeature no esté null antes de usarlo.
  • Agrega una etiqueta personalizada que contiene el origen de marketing de la solicitud a la métrica http.server.request.duration.
    • La etiqueta tiene el nombre mkt_medium y un valor basado en el valor de la cadena de consulta utm_medium. El valor utm_medium se resuelve en un intervalo de valores conocidos.
    • La etiqueta permite clasificar las solicitudes por categoría según el tipo de medio de marketing, lo que podría ser útil al analizar el tráfico de la aplicación web.

Nota

Siga los procedimientos recomendados de métricas multidimensionales al aplicar el enriquecimiento con etiquetas personalizadas. Las etiquetas demasiado numerosas o con un intervalo sin límites crean muchas combinaciones de etiquetas, lo que da lugar a dimensiones elevadas. Las herramientas de recopilación tienen límites en las dimensiones admitidas para un contador y pueden filtrar los resultados para evitar un uso excesivo de memoria.

No participar en métricas HTTP en determinados puntos de conexión y solicitudes

No registrar métricas resulta útil para los puntos de conexión a los que acceden con frecuencia sistemas automatizados, como en las comprobaciones de estado. La grabación de métricas para estas solicitudes suele ser innecesaria. La telemetría no deseada utiliza recursos para recopilar y almacenar, y puede distorsionar los resultados mostrados en un panel de telemetría.

Puede excluir solicitudes HTTP a un punto de conexión de las métricas agregando metadatos, ya sea con el atributo DisableHttpMetrics o el método DisableHttpMetrics :

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();

var app = builder.Build();
app.MapHealthChecks("/healthz").DisableHttpMetrics();
app.Run();

Como alternativa, la IHttpMetricsTagsFeature.MetricsDisabled propiedad se agregó para:

  • Escenarios avanzados en los que una solicitud no se corresponde con un extremo.
  • Deshabilita dinámicamente la recopilación de métricas para solicitudes HTTP específicas.
// Middleware that conditionally opts-out HTTP requests.
app.Use(async (context, next) =>
{
    var metricsFeature = context.Features.Get<IHttpMetricsTagsFeature>();
    if (metricsFeature != null &&
        context.Request.Headers.ContainsKey("x-disable-metrics"))
    {
        metricsFeature.MetricsDisabled = true;
    }

    await next(context);
});

Crear métricas personalizadas

Se crean métricas mediante las API del espacio de nombres System.Diagnostics.Metrics. Para obtener información, consulte Creación de métricas personalizadas.

Creación de métricas en aplicaciones ASP.NET Core con IMeterFactory

Cree instancias de Meter en aplicaciones de ASP.NET Core con IMeterFactory.

ASP.NET Core se registra IMeterFactory en inserción de dependencias (DI) por defecto. La fábrica de contadores integra métricas con DI, lo que facilita el aislamiento y la recopilación de métricas. IMeterFactory es especialmente útil para realizar pruebas. Permite que varias pruebas se ejecuten en paralelo y solo recopilan valores de métricas que se registran en una prueba.

Para utilizar IMeterFactory en una aplicación, cree un tipo que utilice IMeterFactory para crear las métricas personalizadas de la aplicación:

public class ContosoMetrics
{
    private readonly Counter<int> _productSoldCounter;

    public ContosoMetrics(IMeterFactory meterFactory)
    {
        var meter = meterFactory.Create("Contoso.Web");
        _productSoldCounter = meter.CreateCounter<int>("contoso.product.sold");
    }

    public void ProductSold(string productName, int quantity)
    {
        _productSoldCounter.Add(quantity,
            new KeyValuePair<string, object?>("contoso.product.name", productName));
    }
}

Registre el tipo de métrica con DI en Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ContosoMetrics>();

Inserte el tipo de métrica y los valores de registro cuando sea necesario. Dado que el tipo de métrica se registra en la inserción de dependencias, se puede usar con controladores MVC, API mínimas o cualquier otro tipo creado por la inserción de dependencias:

app.MapPost("/complete-sale", (SaleModel model, ContosoMetrics metrics) =>
{
    // ... business logic such as saving the sale to a database ...

    metrics.ProductSold(model.ProductName, model.QuantitySold);
});

Para supervisar el medidor "Contoso.Web", use el siguiente comando dotnet-counters.

dotnet-counters monitor -n WebMetric --counters Contoso.Web

Esto genera una salida similar a la siguiente:

Press p to pause, r to resume, q to quit.
    Status: Running

[Contoso.Web]
    contoso.product.sold (Count / 1 sec)
        contoso.product.name=Eggs            12    
        contoso.product.name=Milk            0    

Visualización de métricas en Grafana con OpenTelemetry y Prometheus

Overview

OpenTelemetry:

  • Es un proyecto de código abierto independiente del proveedor administrado por Cloud Native Computing Foundation.
  • Pretende estandarizar la generación y la recopilación de telemetría para software nativo de nube.
  • Funciona con .NET mediante las API de métricas de .NET.
  • Está aprobado por Azure Monitor y muchos proveedores de APM.

A partir de ASP.NET Core 11, las métricas y seguimientos integrados del servidor HTTP del marco cumplen las partes necesarias de las convenciones semánticas del servidor HTTP de OpenTelemetry. La actividad de solicitud del servidor HTTP emite estos atributos de forma predeterminada y coincide con las métricas integradas. Como resultado, el OpenTelemetry.Instrumentation.AspNetCore paquete NuGet es opcional para recopilar seguimientos y métricas del servidor HTTP. En el ejemplo de este artículo solo se usan los medidores integrados (Microsoft.AspNetCore.Hosting y Microsoft.AspNetCore.Server.Kestrel) y no se hace referencia al paquete de instrumentación. Para obtener la lista de instrumentos integrados y sus atributos, consulte ASP.NET Core métricas HTTP integradas.

Aunque el paquete es opcional, no es un equivalente de la instrumentación integrada. La instrumentación integrada cubre solo las partes necesarias de las convenciones semánticas. Tenga en cuenta las siguientes diferencias antes de quitar el paquete:

  • Algunos atributos de servidor HTTP recomendados no se emiten mediante la instrumentación integrada, como determinados atributos de cliente y red (por ejemplo, client.address). La compatibilidad total con el atributo requerido url.querycondicionalmente, incluida la redacción, también está en curso. Si confía en estos atributos, mantenga el paquete. Para obtener más información, vea dotnet/aspnetcore#65873.
  • El paquete también ofrece una forma sencilla de habilitar la telemetría además del servidor HTTP, incluidos Blazor y SignalR. Para el seguimiento, registra orígenes de actividad adicionales para SignalR (Microsoft.AspNetCore.SignalR.Server en .NET 9 y versiones posteriores) y Blazor (Microsoft.AspNetCore.Components y Microsoft.AspNetCore.Components.Server.Circuits en .NET 10 y versiones posteriores). En el caso de las métricas, habilita los medidores integrados relacionados (como Microsoft.AspNetCore.Components). Sin el paquete, registre los orígenes con AddSource y los medidores con AddMeter usted mismo para recopilar la misma telemetría.

Al agregar telemetría a una aplicación que solo necesita seguimientos y métricas del servidor HTTP, puede confiar en la instrumentación integrada y omitir el paquete. Al actualizar una aplicación existente de .NET 10 a .NET 11 que ya hace referencia al paquete, manténgala si depende de los atributos, orígenes o medidores descritos en la lista anterior. Al eliminar el paquete, se deja de recopilar esa telemetría de forma silenciosa.

Importante

Al habilitar el seguimiento de OpenTelemetry (además de las métricas) sin el OpenTelemetry.Instrumentation.AspNetCore paquete, registre el servidor ActivitySource HTTP del marco para que se registre la actividad de solicitud. El origen de actividad del servidor HTTP de ASP.NET Core se denomina Microsoft.AspNetCore y el marco crea una actividad de solicitud denominada Microsoft.AspNetCore.Hosting.HttpRequestIn para cada petición a fin de propagar el contexto de seguimiento. Si el origen Microsoft.AspNetCore no está registrado en el SDK de OpenTelemetry, la actividad de la solicitud no se registra y el muestreador predeterminado ParentBased descarta silenciosamente cualquier tramo secundario personalizado iniciado durante la solicitud.

En la canalización de seguimiento existente, registre el origen explícitamente:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddSource("Microsoft.AspNetCore")
        .AddSource("MyApp"));

En el ejemplo anterior:

  • AddSource("Microsoft.AspNetCore") registra el origen de actividad del servidor HTTP de ASP.NET Core para que se registre la actividad de la solicitud.
  • AddSource("MyApp") registra el propio ActivitySource de la aplicación. Reemplace por MyApp el nombre que usa la aplicación.
  • No se muestra un exportador. En este ejemplo se supone que un exportador ya está configurado en la canalización de seguimiento.

Como alternativa, llame AddAspNetCoreInstrumentation() desde el OpenTelemetry.Instrumentation.AspNetCore paquete, que registra el origen automáticamente.

Este tutorial muestra una de las integraciones que hay disponibles para las métricas de OpenTelemetry mediante los proyectos de OSS Prometheus y Grafana. El flujo de datos de métricas:

  1. Las API de métricas de ASP.NET Core registran medidas de la aplicación de ejemplo.

  2. La biblioteca de .NET de OpenTelemetry que se ejecuta en la aplicación agrega las medidas.

  3. La biblioteca exportadora de Prometheus hace que los datos agregados estén disponibles a través de un punto de conexión de métricas HTTP. "Exportador" es el término que OpenTelemetry usa para denominar a las bibliotecas que transmiten telemetría a back-ends específicos del proveedor.

  4. Un servidor de Prometheus:

    • Sondea el punto de conexión de métricas.
    • Lee los datos.
    • Almacena los datos en una base de datos para la persistencia a largo plazo. Prometheus hace referencia a la lectura y el almacenamiento de datos como extracción de un punto de conexión.
    • Se puede ejecutar en una máquina diferente.
  5. El servidor de Grafana:

    • Consulta los datos almacenados en Prometheus y los muestra en un panel de supervisión basado en web.
    • Se puede ejecutar en una máquina diferente.

Visualizar métricas de una aplicación de ejemplo

Vaya a la aplicación de ejemplo. El navegador muestra Hello OpenTelemetry! ticks:<3digits>, donde 3digits son los tres últimos dígitos de DateTime.Ticks actual.

Anexe /metrics a la dirección URL para ver el punto de conexión de métricas. El explorador muestra las métricas que se recopilan:

métricas 2

Configuración de Prometheus

Siga los primeros pasos de Prometheus para configurar un servidor de Prometheus y confirmar que funciona.

Modifique el archivo de configuración prometheus.yml para que Prometheus recopile métricas del endpoint que expone la aplicación de ejemplo. Agregue el siguiente texto resaltado en la sección scrape_configs:

# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]

  - job_name: 'MyASPNETApp'
    scrape_interval: 5s # Poll every 5 seconds for a more responsive demo.
    static_configs:
      - targets: ["localhost:5045"]  ## Enter the HTTP port number of the demo app.

En el código YAML resaltado anterior, reemplace por 5045 el número de puerto que usa la aplicación de ejemplo.

Iniciar Prometheus

  1. Vuelva a cargar la configuración o reinicie el servidor de Prometheus.
  2. Confirme que OpenTelemetryTest se encuentre en el estado UP en la página Estado>Objetivos del portal web de Prometheus.

Estado de Prometheus

Seleccione el icono Abrir explorador de métricas para ver las métricas disponibles:

Prometheus open_metric_exp

Escriba una categoría de contador como http_ en el cuadro Entrada de expresión para ver las métricas disponibles:

métricas disponibles

Como alternativa, escriba una categoría de contador como kestrel en el cuadro Entrada de expresión para ver las métricas disponibles:

Prometheus kestrel

Visualización de métricas en un panel de Grafana

dashboard-screenshot2

Probar métricas en aplicaciones de ASP.NET Core

Puede probar las métricas en ASP.NET Core aplicaciones. Una manera de hacerlo es recopilar y declarar valores de métricas en ASP.NET Core pruebas de integración mediante MetricCollector<T>.

public class BasicTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;
    public BasicTests(WebApplicationFactory<Program> factory) => _factory = factory;

    [Fact]
    public async Task Get_RequestCounterIncreased()
    {
        // Arrange
        var client = _factory.CreateClient();
        var meterFactory = _factory.Services.GetRequiredService<IMeterFactory>();
        var collector = new MetricCollector<double>(meterFactory,
            "Microsoft.AspNetCore.Hosting", "http.server.request.duration");

        // Act
        var response = await client.GetAsync("/");

        // Assert
        Assert.Contains("Hello OpenTelemetry!", await response.Content.ReadAsStringAsync());

        await collector.WaitForMeasurementsAsync(minCount: 1).WaitAsync(TimeSpan.FromSeconds(5));
        Assert.Collection(collector.GetMeasurementSnapshot(),
            measurement =>
            {
                Assert.Equal("http", measurement.Tags["url.scheme"]);
                Assert.Equal("GET", measurement.Tags["http.request.method"]);
                Assert.Equal("/", measurement.Tags["http.route"]);
            });
    }
}

La prueba anterior:

  • Arranca una aplicación web en memoria con WebApplicationFactory<TEntryPoint>. Program en el argumento genérico de la fábrica especifica la aplicación web.
  • Recopila valores de métricas con MetricCollector<T>
    • Requiere una referencia de paquete a Microsoft.Extensions.Diagnostics.Testing.
    • Se crea MetricCollector<T> mediante la aplicación web IMeterFactory. Esto permite que el recopilador informe solo de los valores de métricas registrados por prueba.
    • Incluye el nombre del medidor, Microsoft.AspNetCore.Hosting, y el nombre del contador, http.server.request.duration que se va a recopilar.
  • Realiza una solicitud HTTP a la aplicación web.
  • Aserte la prueba mediante el uso de los resultados del recopilador de métricas.

métricas de ASP.NET Core Identity

La observabilidad de ASP.NET Core Identity ayuda a monitorizar las actividades de gestión de usuarios y los procesos de autenticación.

Las métricas se encuentran en el Microsoft.AspNetCore.Identity medidor y se describen en las secciones siguientes.

Métricas de administración de usuarios

  • aspnetcore.identity.user.create.duration mide la duración de las operaciones de creación de usuarios.
  • aspnetcore.identity.user.update.duration mide la duración de las operaciones de actualización de usuario.
  • aspnetcore.identity.user.delete.duration mide la duración de las operaciones de eliminación de usuarios.
  • aspnetcore.identity.user.check_password_attempts cuenta los intentos de comprobación de contraseña.
  • aspnetcore.identity.user.generated_tokens cuenta los tokens generados para los usuarios, como los tokens de restablecimiento de contraseña.
  • aspnetcore.identity.user.verify_token_attempts cuenta los intentos de verificación de tokens.

Métricas de autenticación

  • aspnetcore.identity.sign_in.authenticate.duration mide la duración de las operaciones de autenticación.
  • aspnetcore.identity.sign_in.check_password_attempts cuenta los intentos de comprobación de contraseña durante el inicio de sesión.
  • aspnetcore.identity.sign_in.sign_ins cuenta inicios de sesión exitosos.
  • aspnetcore.identity.sign_in.sign_outs cuenta las desconexiones.
  • aspnetcore.identity.sign_in.two_factor_clients_remembered cuenta clientes de autenticación de dos factores recordados.
  • aspnetcore.identity.sign_in.two_factor_clients_forgotten cuenta clientes olvidados de autenticación de dos factores.

Use estas métricas para:

  • Supervise el registro y la administración de usuarios.
  • Realice un seguimiento de los patrones de autenticación y posibles problemas de seguridad.
  • Mida el rendimiento de las operaciones de Identity.
  • Observe el uso de la autenticación en dos fases.

Visualización de Identity métricas

Use dotnet-counters para ver estas métricas y supervisarlas en tiempo real. O bien, expórtelos a Prometheus y visualícelas en Grafana mediante las técnicas descritas anteriormente en este artículo.

Por ejemplo, para monitorear todas las Identity métricas con dotnet-counters:

dotnet-counters monitor -n YourAppName --counters Microsoft.AspNetCore.Identity

Contadores y medidores de ASP.NET Core

Para obtener una lista de medidores y contadores de ASP.NET Core, consulte métricas de ASP.NET Core. En ASP.NET Core 11 y versiones posteriores, los medidores de servidor HTTP integrados (por ejemplo, Microsoft.AspNetCore.Hosting y Microsoft.AspNetCore.Server.Kestrel) emiten datos que se ajustan a las partes necesarias de las convenciones semánticas del servidor HTTP de OpenTelemetry. Puede consumir estos medidores con el SDK de OpenTelemetry sin el OpenTelemetry.Instrumentation.AspNetCore paquete.