Métricas do ASP.NET Core

As métricas são medidas numéricas relatadas ao longo do tempo. Use-os 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 é necessário para responder.
  • Respostas que envia com erro.

Relate essas métricas a um sistema de monitoramento em intervalos regulares. Configure painéis para exibir métricas e criar alertas 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.

A lista abrangente de todos os instrumentos junto com seus atributos é descrita em ASP.NET Core métricas internas.

Usar métricas

O uso de métricas envolve o seguinte:

  • 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 e armazenamento: Um aplicativo .NET configura as métricas nomeadas a serem transmitidas do aplicativo para armazenamento e análise externos. Algumas ferramentas podem executar a configuração fora do aplicativo usando arquivos de configuração ou uma ferramenta de interface do usuário.
  • Visualização: Uma ferramenta que pode exibir as métricas em um formato legível por humanos. Por exemplo, Grafana e Prometheus.
  • Alertando: Uma ferramenta que fornece notificações quando uma métrica excede um limite. Por exemplo, se o tempo médio de resposta de um serviço Web exceder 400 ms, um alerta poderá ser enviado para a equipe de operações.
  • Análise: Uma ferramenta que pode analisar as métricas ao longo do tempo. Essa ferramenta geralmente é um painel baseado na Web que pode ser personalizado para mostrar as métricas mais importantes para um aplicativo específico.

O código instrumentado pode registrar medidas numéricas, mas para criar métricas úteis para monitoramento, você precisa agregar, transmitir e armazenar as medidas. O processo de agregação, transmissão e armazenamento de dados é chamado de coleta. Este tutorial mostra vários exemplos de coleta e exibição de métricas:

Você também pode associar medições a pares chave-valor chamados tags, que permitem categorizar os dados 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 seguinte código:

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

o dotnet-counters é uma ferramenta de linha de comando que pode exibir métricas dinâmicas para aplicativos .NET 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, consulte 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 tags, como a rota correspondente e o código de status da resposta.

A métrica http.server.request.duration é compatível com o enriquecimento de tags usando IHttpMetricsTagsFeature. Enriquecimento ocorre quando uma biblioteca ou aplicativo adiciona tags próprias a uma métrica. Esse recurso será útil se um aplicativo quiser adicionar uma categorização personalizada a dashboards 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 anterior:

  • 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 ouvindo a métrica. Verifique se IHttpMetricsTagsFeature não é null antes de usá-lo.
  • Adiciona uma tag personalizada contendo a origem de marketing da solicitação à métrica http.server.request.duration.
    • A tag tem o nome mkt_medium e um valor com base no valor do parâmetro de consulta utm_medium. O valor utm_medium é resolvido em um intervalo conhecido de valores.
    • A tag permite que as requisições sejam classificadas por tipo de canal de marketing, o que pode ser útil ao analisar o tráfego do aplicativo web.

Observação

Siga as melhores práticas de métricas multidimensionais ao enriquecer com tags personalizadas. Tags que são muito numerosas ou têm um intervalo não vinculado criam muitas combinações de tags, resultando em altas dimensões. As ferramentas de coleção têm limites em dimensões com suporte para um contador e podem filtrar resultados para evitar o uso excessivo de memória.

Desativar métricas HTTP em determinados endpoints e solicitações

Optar por não registrar métricas é benéfico para endpoints frequentemente chamados por sistemas automatizados, como verificações de saúde. O registro de métricas para essas solicitações geralmente é desnecessário. A telemetria indesejada usa recursos para coletar e armazenar e pode distorcer os resultados exibidos em um painel de telemetria.

Você pode excluir das métricas as solicitações HTTP para um endpoint adicionando metadados, com o atributo DisableHttpMetrics ou o método DisableHttpMetrics:

  • Adicione o atributo DisableHttpMetrics ao controlador de API Web, SignalR hub ou serviço gRPC.
  • Chame DisableHttpMetrics durante o mapeamento dos endpoints na inicialização do aplicativo:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();

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

Como alternativa, a IHttpMetricsTagsFeature.MetricsDisabled propriedade foi adicionada para:

  • Cenários avançados em que uma solicitação não está associada a um endpoint.
  • Desabilitar dinamicamente a coleta de métricas para solicitações 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);
});

Criar métricas personalizadas

Você cria métricas usando APIs no namespace System.Diagnostics.Metrics. Para obter informações, consulte Criar métricas personalizadas.

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

Criar instâncias de Meter em aplicativos 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 coleta 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 valores de registro 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    

Visualizar métricas no Grafana com OpenTelemetry e Prometheus

Overview

OpenTelemetry:

  • É um projeto de código aberto neutro em relação a fornecedores, apoiado pela 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.

A partir da versão 11 do ASP.NET Core, as métricas e os rastreamentos integrados do servidor HTTP do framework estão em conformidade com os requisitos das partes necessárias das convenções semânticas do servidor HTTP do OpenTelemetry. A atividade de solicitação do servidor HTTP emite esses atributos por padrão, correspondendo às métricas internas. Como resultado, o OpenTelemetry.Instrumentation.AspNetCore pacote NuGet é opcional para coletar métricas e rastreamentos do servidor HTTP. O exemplo neste artigo usa apenas os medidores internos (Microsoft.AspNetCore.Hosting e Microsoft.AspNetCore.Server.Kestrel) e não faz referência ao pacote de instrumentação. Para obter a lista de instrumentos internos e seus atributos, consulte ASP.NET Core métricas HTTP internas.

Embora o pacote seja opcional, ele não é um substituto direto da instrumentação integrada. A instrumentação interna abrange apenas as partes necessárias das convenções semânticas. Considere as seguintes diferenças antes de remover o pacote:

  • Alguns atributos de servidor HTTP recomendados não são emitidos pela instrumentação interna, como determinados atributos de cliente e de rede (por exemplo, client.address). O suporte total para o atributo condicionalmente necessáriourl.query, incluindo a edição, também ainda está em andamento. Se você depender desses atributos, mantenha o pacote. Para obter mais informações, consulte dotnet/aspnetcore#65873.
  • O pacote também facilita a habilitação da telemetria além do servidor HTTP, incluindo Blazor e SignalR. Para rastreamento, ele registra fontes de atividade extras para SignalR (Microsoft.AspNetCore.SignalR.Server em .NET 9 e posterior) e Blazor (Microsoft.AspNetCore.Components e Microsoft.AspNetCore.Components.Server.Circuits em .NET 10 e posterior). Para métricas, ele habilita os medidores internos relacionados (como Microsoft.AspNetCore.Components). Sem o pacote, registre você mesmo as fontes com AddSource e os medidores com AddMeter para coletar a mesma telemetria.

Ao adicionar telemetria a um aplicativo que só precisa de métricas e rastreamentos do servidor HTTP, você pode contar com a instrumentação interna e omitir o pacote. Ao atualizar um aplicativo existente do .NET 10 para o .NET 11 que já faz referência ao pacote, mantenha-o se depender dos atributos, fontes ou medidores descritos na lista anterior. A remoção do pacote faz com que essa telemetria seja descartada sem aviso.

Importante

Ao habilitar o rastreamento do OpenTelemetry (além das métricas) sem o pacote OpenTelemetry.Instrumentation.AspNetCore, registre o servidor HTTP ActivitySource do framework para que a atividade da solicitação seja registrada. A fonte de atividade do servidor HTTP do ASP.NET Core é nomeada Microsoft.AspNetCoree a estrutura cria uma atividade de solicitação nomeada Microsoft.AspNetCore.Hosting.HttpRequestIn para cada solicitação para propagar o contexto de rastreamento. Se a origem Microsoft.AspNetCore não estiver registrada no SDK do OpenTelemetry, a atividade da solicitação não será gravada, e a amostra padrão ParentBased descartará silenciosamente todas as expansões filho personalizadas iniciadas durante a solicitação.

No seu pipeline de rastreamento existente, registre a origem explicitamente:

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

No exemplo anterior:

  • AddSource("Microsoft.AspNetCore")registra a origem da atividade do servidor HTTP do ASP.NET Core para que a atividade de solicitação seja registrada.
  • AddSource("MyApp") registra o ActivitySource do próprio aplicativo. Substitua MyApp pelo nome que seu aplicativo usa.
  • Um exportador não é mostrado. Este exemplo pressupõe que um exportador já esteja configurado no pipeline de rastreamento.

Como alternativa, chame AddAspNetCoreInstrumentation() direto do pacote OpenTelemetry.Instrumentation.AspNetCore, que registra a origem para você.

Este tutorial mostra uma das integrações disponíveis para métricas do OpenTelemetry usando os projetos OSS Prometheus e 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 endpoint de métricas HTTP. 'Exportador' é o termo que o OpenTelemetry usa para 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

Vá para o aplicativo de exemplo. O navegador mostra Hello OpenTelemetry! ticks:<3digits>, em que 3digits correspondem aos últimos três dígitos do DateTime.Ticks atual.

Anexe /metrics ao final da URL para visualizar o endpoint 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 colete o endpoint de métricas que a aplicação de exemplo expõe. Adicione o seguinte texto realçado na scrape_configs seção:

# 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 anterior, substitua 5045 pelo número de porta que o aplicativo de exemplo usa.

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 uma categoria de contador, como http_ na caixa de entrada Expressão , para ver as métricas disponíveis:

Métricas disponíveis

Como alternativa, insira uma categoria de 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

Você pode testar métricas em aplicativos ASP.NET Core. Uma maneira de fazer isso é coletar e afirmar valores de métricas em testes de integração 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 anterior:

  • Inicializa um aplicativo Web na memória com WebApplicationFactory<TEntryPoint>. Program no argumento genérico da fábrica especifica o aplicativo Web.
  • Coleta os valores das 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 informe apenas os valores das 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.
  • Valida o teste com base nos resultados do coletor de métricas.

Métricas do ASP.NET Core Identity

A observabilidade do ASP.NET Core Identity ajuda você a monitorar as atividades de gerenciamento de usuários e os processos de autenticação.

As métricas estão no Microsoft.AspNetCore.Identity medidor e são descritas nas seções a seguir.

Métricas de gerenciamento de usuário

  • aspnetcore.identity.user.create.duration mede a duração das operações de criação do usuário.
  • aspnetcore.identity.user.update.duration mede a duração das operações de atualização do usuário.
  • aspnetcore.identity.user.delete.duration mede a duração das operações de exclusão de usuário.
  • aspnetcore.identity.user.check_password_attempts conta tentativas de verificação de senha.
  • aspnetcore.identity.user.generated_tokens conta tokens gerados para usuários, como tokens de redefinição de senha.
  • aspnetcore.identity.user.verify_token_attempts conta tentativas de verificação de token.

Métricas de autenticação

  • aspnetcore.identity.sign_in.authenticate.duration mede a duração das operações de autenticação.
  • aspnetcore.identity.sign_in.check_password_attempts conta tentativas de verificação de senha durante a entrada.
  • aspnetcore.identity.sign_in.sign_ins conta entradas bem-sucedidas.
  • aspnetcore.identity.sign_in.sign_outs conta as saídas.
  • aspnetcore.identity.sign_in.two_factor_clients_remembered conta clientes de autenticação de dois fatores lembrados.
  • aspnetcore.identity.sign_in.two_factor_clients_forgotten conta clientes de autenticação em dois fatores esquecidos.

Use estas métricas para:

  • Monitore o registro e o gerenciamento do usuário.
  • Acompanhe os padrões de autenticação e possíveis problemas de segurança.
  • Medir o desempenho das Identity operações.
  • Observe o uso de autenticação de dois fatores.

Exibindo Identity métricas

Use dotnet-counters para exibir essas métricas e monitorá-las em tempo real. Ou exporte-os para Prometheus e visualize-os no Grafana usando as técnicas descritas anteriormente neste artigo.

Por exemplo, para monitorar todas as Identity métricas com dotnet-counters:

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

Medidores e contadores do ASP.NET Core

Para obter uma lista de ASP.NET Core medidores e contadores, consulte ASP.NET Core métricas. Em ASP.NET Core 11 e posteriores, os medidores de servidor HTTP internos (por exemplo, Microsoft.AspNetCore.Hosting e Microsoft.AspNetCore.Server.Kestrel) emitem dados em conformidade com as partes necessárias das convenções semânticas do servidor HTTP openTelemetry. Você pode consumir esses medidores com o SDK do OpenTelemetry sem o pacote OpenTelemetry.Instrumentation.AspNetCore.