Compartilhar via


Métricas do ASP.NET Core

As métricas são medidas numéricas relatadas ao longo do tempo. Normalmente, elas são usadas para monitorar a integridade de um aplicativo e gerar alertas. Por exemplo, um serviço Web pode acompanhar a quantidade de:

  • Solicitações recebidas por segundo.
  • Milissegundos que foram necessários para responder.
  • As respostas enviaram um erro.

Essas métricas podem ser relatadas a um sistema de monitoramento em intervalos regulares. Os painéis podem ser configurados para exibir métricas e alertas criados para notificar as pessoas sobre problemas. Se o serviço Web for destinado a responder a solicitações dentro de 400 ms e começar a responder em 600 ms, o sistema de monitoramento poderá notificar a equipe de operações de que a resposta do aplicativo está mais lenta do que o normal.

Dica

Consulte as métricas do ASP.NET Core para obter uma lista abrangente de todos os instrumentos junto aos seus atributos.

Usando métricas

Há duas partes para usar métricas em um aplicativo .NET:

  • Instrumentação: O código em bibliotecas do .NET faz medições e associa essas medidas a um nome de métrica. O .NET e o ASP.NET Core incluem muitas métricas internas.
  • Coleção: um aplicativo .NET configura as métricas nomeadas para serem transmitidas do aplicativo para armazenamento externo e análise. Algumas ferramentas podem executar a configuração fora do aplicativo usando arquivos de configuração ou uma ferramenta de interface do usuário.

O código instrumentado pode registrar medidas numéricas, mas elas precisam ser agregadas, transmitidas e armazenadas para criar métricas úteis para o monitoramento. O processo de agregação, transmissão e armazenamento de dados é chamado de coleta. Este tutorial mostra vários exemplos de coleta de métricas:

As medidas também podem ser associadas a pares chave-valor chamados de marcas, que permitem que os dados sejam categorizados para análise. Para obter mais informações, confira Métricas multidimensionais.

Criar o aplicativo inicial

Crie um novo aplicativo ASP.NET Core com o seguinte comando:

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

Substitua o conteúdo de Program.cs pelo fornecido a seguir:

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();

Exibir métricas com dotnet-counters

dotnet-counters é uma ferramenta de linha de comando simples que pode exibir métricas dinâmicas para qualquer aplicativo .NET Core sob demanda. Ela não requer configuração, tornando-a útil para investigações ad hoc ou verificando se a instrumentação de métrica está funcionando. Ele funciona com APIs baseadas em System.Diagnostics.Metrics e EventCounters.

Se a ferramenta dotnet-counters não estiver instalada, execute o seguinte comando:

dotnet tool update -g dotnet-counters

Enquanto o aplicativo de teste estiver em execução, inicie o dotnet-counters. O comando a seguir mostra um exemplo de dotnet-countersmonitoramento de todas as métricas a partir do Microsoft.AspNetCore.Hostingmedidor.

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

Uma saída semelhante à apresentada a seguir será exibida:

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 obter mais informações, confira dotnet-counters.

Enriquecer a métrica de solicitação do ASP.NET Core

O ASP.NET Core tem muitas métricas internas. A métrica http.server.request.duration:

  • Registra a duração das solicitações HTTP no servidor.
  • Captura informações da solicitação em marcas, como a rota correspondente e o código do status da resposta.

A métrica http.server.request.duration dá suporte ao enriquecimento de marcas utilizando IHttpMetricsTagsFeature. Enriquecimento é quando uma biblioteca ou aplicativo adiciona suas próprias marcas a uma métrica. Isso será útil se um aplicativo desejar adicionar uma categorização personalizada a painéis ou alertas criados com 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();

O exemplo de continuação:

  • Adiciona um middleware para enriquecer a métrica de solicitação do ASP.NET Core.
  • Obtém o IHttpMetricsTagsFeature do HttpContext. O recurso estará presente no contexto somente se alguém estiver escutando a métrica. Verifique se IHttpMetricsTagsFeature não é null antes de usá-lo.
  • Adiciona uma marca personalizada contendo a origem de marketing da solicitação para a métrica http.server.request.duration.
    • A marca tem o nome mkt_medium e um valor com base no valor da cadeia de caracteres de consulta utm_medium. O valor utm_medium é resolvido em um intervalo conhecido de valores.
    • A marca permite que as solicitações sejam categorizadas por tipo de meio de marketing, o que pode ser útil ao analisar o tráfego de aplicativos Web.

Observação

Siga as melhores práticas de métricas multidimensionais ao enriquecer com marcas personalizadas. Um número excessivo de marcas ou marcas com um intervalo não vinculado causam uma grande combinação de marcas. As ferramentas de coleta têm um limite de quantas combinações dão suporte para um contador e podem começar a filtrar os resultados para evitar o uso excessivo da memória.

Criar métricas personalizadas

As métricas são criadas usando APIs no namespace System.Diagnostics.Metrics. Confira Criar métricas personalizadas para obter informações sobre como criar métricas personalizadas.

Criação de métricas em aplicativos do ASP.NET Core com IMeterFactory

Recomendamos a criação de instâncias Meter em aplicativos do ASP.NET Core com IMeterFactory.

O ASP.NET Core registra IMeterFactory na DI (injeção de dependência) por padrão. A fábrica de medidores integra as métricas à DI, facilitando a isolação e a coleta de métricas. IMeterFactory é especialmente útil para testes. Ele permite que vários testes sejam executados lado a lado e coletam apenas valores de métricas registrados em um teste.

Para usar IMeterFactory em um aplicativo, crie um tipo que usa IMeterFactory para criar as métricas personalizadas do aplicativo:

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 o tipo de métrica com DI em Program.cs:

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

Insira o tipo de métrica e os registre os valores quando necessário. Como o tipo de métrica é registrado em DI, ele pode ser usado com controladores MVC, APIs mínimas ou qualquer outro tipo criado por DI:

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 monitorar o medidor "Contoso.Web", use o comando dotnet-counters a seguir.

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

Uma saída semelhante à apresentada a seguir será exibida:

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    

Preencher métricas no Grafana com OpenTelemetry e Prometheus.

Visão geral

OpenTelemetry:

  • É um projeto de software livre neutro do fornecedor compatível com o Cloud Native Computing Foundation.
  • Padroniza a geração e coleta de telemetria para software nativo de nuvem.
  • Funciona com o .NET usando as APIs de métrica do .NET.
  • É endossado pelo Azure Monitor e por muitos fornecedores do APM.

Este tutorial mostra uma das integrações disponíveis para métricas OpenTelemetry usando os projetos do Prometheus e do Grafana. O fluxo de dados de métricas:

  1. As APIs de métricas do ASP.NET Core registram medidas do aplicativo de exemplo.

  2. A biblioteca OpenTelemetry .NET em execução no aplicativo agrega as medições.

  3. A biblioteca do exportador prometheus disponibiliza os dados agregados por meio de um ponto de extremidade de métricas HTTP. 'Exportador' é o que o OpenTelemetry chama as bibliotecas que transmitem telemetria para back-ends específicos do fornecedor.

  4. Um servidor Prometheus:

    • Sonda o ponto de extremidade de métricas
    • Lê os dados
    • Armazena os dados em um banco de dados para persistência de longo prazo. Prometheus refere-se à leitura e armazenamento de dados como extração de um ponto de extremidade.
    • Pode ser executado em um computador diferente
  5. O servidor Grafana:

    • Consulta os dados armazenados no Prometheus e os exibe em um painel de monitoramento baseado na Web.
    • Pode ser executado em um computador diferente.

Exibir métricas do aplicativo de exemplo

Navegue até o aplicativo de exemplo. O navegador Hello OpenTelemetry! ticks:<3digits> exibe 3digits onde estão os três últimos dígitos do DateTime.Ticks atual.

Acrescente /metrics à URL para exibir o ponto de extremidade de métricas. O navegador exibe as métricas que estão sendo coletadas:

métricas 2

Instalar e configurar o Prometheus

Siga as primeiras etapas do Prometheus para configurar um servidor Prometheus e confirmar se ele está funcionando.

Modifique o arquivo de configuração prometheus.yml para que o Prometheus extraia o ponto de extremidade de métricas que nosso aplicativo de exemplo está expondo. Adicione o seguinte texto realçado na seção 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.

No YAML realçado anteriormente, substitua 5045 pelo número da porta em que o aplicativo de exemplo está sendo executado.

Iniciar o Prometheus

  1. Recarregue a configuração ou reinicie o servidor Prometheus.
  2. Confirme se o OpenTelemetryTest está no estado UP na página Status>Destinos do portal da Web Prometheus.

status do Prometheus

Selecione o ícone Abrir gerenciador de métricas para ver as métricas disponíveis:

Prometheus open_metric_exp

Insira a categoria do contador, como http_ na caixa de entrada Expressão, para ver as métricas disponíveis:

métricas disponíveis

Como alternativa, insira a categoria do contador, como kestrel, na caixa de entrada Expressão, para ver as métricas disponíveis:

Prometheus kestrel

Mostrar métricas em um painel do Grafana

dashboard-screenshot2

Testar métricas em aplicativos do ASP.NET Core

É possível testar as métricas em aplicativos do ASP.NET Core. Uma maneira de fazer isso é coletar e declarar valores de métricas nos testes de integração do ASP.NET Core usando 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"]);
            });
    }
}

O teste em andamento:

  • Inicializa um aplicativo Web na memória com WebApplicationFactory<TEntryPoint>. Program no argumento genérico da fábrica especifica o aplicativo Web.
  • Coleta valores de métricas com MetricCollector<T>
    • Requer uma referência de pacote para Microsoft.Extensions.Diagnostics.Testing
    • O MetricCollector<T> é criado usando o IMeterFactory do aplicativo Web. Isso permite que o coletor relate apenas os valores de métricas registrados por teste.
    • Inclui o nome do medidor, Microsoft.AspNetCore.Hosting, e o nome do contador, http.server.request.duration, para coletar.
  • Faz uma solicitação HTTP para o aplicativo Web.
  • Declara os valores do teste usando os resultados do coletor de métricas.

Medidores e contadores do ASP.NET Core

Consulte as métricas do ASP.NET Core para obter uma lista de medidores e contadores do ASP.NET Core.