Coleção de métricas personalizadas no .NET e no .NET Core

Os SDKs do Azure Monitor Application Insights .NET e .NET Core têm dois métodos diferentes de coleta de métricas personalizadas: TrackMetric() e GetMetric(). A principal diferença entre esses dois métodos é a agregação local. O TrackMetric() método carece de pré-agregação. O GetMetric() método tem pré-agregação. Recomendamos que você use a agregação, portanto TrackMetric() , não é mais o método preferido de coleta de métricas personalizadas. Este artigo orienta você sobre o uso do GetMetric() método e alguns dos fundamentos por trás de como ele funciona.

Nota

A documentação a seguir depende da API clássica do Application Insights. O plano de longo prazo para o Application Insights é coletar dados usando OpenTelemetry. Para obter mais informações, consulte Habilitar o Azure Monitor OpenTelemetry para aplicativos .NET, Node.js, Python e Java.

API pré-agregante vs. API não pré-agregante

O TrackMetric() método envia telemetria bruta denotando uma métrica. É ineficiente enviar um único item de telemetria para cada valor. O TrackMetric() método também é ineficiente em termos de desempenho porque todos TrackMetric(item) passam pelo pipeline SDK completo de inicializadores e processadores de telemetria.

Ao contrário TrackMetric()do , lida com a pré-agregação local para você e, em seguida, GetMetric() envia apenas uma métrica de resumo agregado em um intervalo fixo de um minuto. Se você precisar monitorar de perto alguma métrica personalizada no segundo ou até mesmo milissegundo nível, poderá fazê-lo incorrendo apenas no custo de armazenamento e tráfego de rede de monitorar apenas a cada minuto. Esse comportamento também reduz muito o risco de ocorrência de limitação porque o número total de itens de telemetria que precisam ser enviados para uma métrica agregada é muito reduzido.

No Application Insights, as métricas personalizadas coletadas por meio TrackMetric()GetMetric() e não estão sujeitas a amostragem. A amostragem de métricas importantes pode levar a cenários em que os alertas que você pode ter criado em torno dessas métricas podem se tornar não confiáveis. Ao nunca fazer a amostragem de suas métricas personalizadas, você geralmente pode ter certeza de que, quando seus limites de alerta são violados, um alerta é acionado. Como as métricas personalizadas não são amostradas, há algumas preocupações potenciais.

O acompanhamento de tendências em uma métrica a cada segundo, ou em um intervalo ainda mais granular, pode resultar em:

  • Aumento dos custos de armazenamento de dados. Há um custo associado à quantidade de dados que você envia para o Azure Monitor. Quanto mais dados você enviar, maior será o custo geral do monitoramento.
  • Aumento do tráfego de rede ou sobrecarga de desempenho. Em alguns cenários, essa sobrecarga pode ter um custo monetário e de desempenho do aplicativo.
  • Risco de limitação da ingestão. O Azure Monitor descarta ("limita") pontos de dados quando seu aplicativo envia uma alta taxa de telemetria em um curto intervalo de tempo.

A limitação é uma preocupação porque pode levar a alertas perdidos. A condição para disparar um alerta pode ocorrer localmente e, em seguida, ser descartada no ponto de extremidade de ingestão devido ao envio de muitos dados. Não recomendamos o uso TrackMetric() para .NET e .NET Core, a menos que você tenha implementado sua própria lógica de agregação local. Se você estiver tentando rastrear todas as instâncias em que um evento ocorre durante um determinado período de tempo, talvez ache que TrackEvent() é uma opção melhor. Lembre-se de que, ao contrário das métricas personalizadas, os eventos personalizados estão sujeitos a amostragem. Você ainda pode usar TrackMetric() mesmo sem escrever sua própria pré-agregação local. Mas se o fizer, esteja ciente das armadilhas.

Em resumo, recomendamos GetMetric() porque faz pré-agregação, acumula valores de todas as Track() chamadas e envia um resumo/agregado uma vez a cada minuto. O GetMetric() método pode reduzir significativamente o custo e a sobrecarga de desempenho enviando menos pontos de dados enquanto ainda coleta todas as informações relevantes.

Nota

Somente os SDKs .NET e .NET Core têm um GetMetric() método. Se você estiver usando Java, consulte Enviando métricas personalizadas usando micrômetro. Para JavaScript e Node.js, você ainda usaria TrackMetric()o , mas tenha em mente as advertências descritas na seção anterior. Para Python, você pode usar OpenCensus.stats para enviar métricas personalizadas , mas a implementação de métricas é diferente.

Introdução ao GetMetric

Para nossos exemplos, vamos usar um aplicativo de serviço de trabalho .NET Core 3.1 básico. Se você quiser replicar o ambiente de teste usado com esses exemplos, siga as etapas de 1 a 6 no artigo Serviço de trabalho de monitoramento. Estas etapas adicionam o Application Insights a um modelo de projeto de serviço de trabalho básico. Os conceitos se aplicam a qualquer aplicativo geral em que o SDK possa ser usado, incluindo aplicativos Web e aplicativos de console.

Enviar métricas

Substitua o conteúdo do arquivo worker.cs pelo seguinte código:

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.ApplicationInsights;

namespace WorkerService3
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private TelemetryClient _telemetryClient;

        public Worker(ILogger<Worker> logger, TelemetryClient tc)
        {
            _logger = logger;
            _telemetryClient = tc;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {   // The following line demonstrates usages of GetMetric API.
            // Here "computersSold", a custom metric name, is being tracked with a value of 42 every second.
            while (!stoppingToken.IsCancellationRequested)
            {
                _telemetryClient.GetMetric("ComputersSold").TrackValue(42);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

Quando você executa o código de exemplo, você vê o while loop repetidamente em execução sem telemetria sendo enviada na janela de saída do Visual Studio. Um único item de telemetria é enviado por volta da marca de 60 segundos, que em nosso teste se parece com:

Application Insights Telemetry: {"name":"Microsoft.ApplicationInsights.Dev.00000000-0000-0000-0000-000000000000.Metric", "time":"2019-12-28T00:54:19.0000000Z",
"ikey":"00000000-0000-0000-0000-000000000000",
"tags":{"ai.application.ver":"1.0.0.0",
"ai.cloud.roleInstance":"Test-Computer-Name",
"ai.internal.sdkVersion":"m-agg2c:2.12.0-21496",
"ai.internal.nodeName":"Test-Computer-Name"},
"data":{"baseType":"MetricData",
"baseData":{"ver":2,"metrics":[{"name":"ComputersSold",
"kind":"Aggregation",
"value":1722,
"count":41,
"min":42,
"max":42,
"stdDev":0}],
"properties":{"_MS.AggregationIntervalMs":"42000",
"DeveloperMode":"true"}}}}

Este único item de telemetria representa um agregado de 41 medições métricas distintas. Como estávamos enviando o mesmo valor repetidamente, temos um desvio padrão () com 0 valores máximos () e mínimos (maxstDevmin) idênticos. A value propriedade representa uma soma de todos os valores individuais que foram agregados.

Nota

O GetMetric método não suporta o rastreamento do último valor (por exemplo, gauge) ou o rastreamento de histogramas ou distribuições.

Se examinarmos nosso recurso do Application Insights na experiência de Logs (Analytics), o item de telemetria individual se parecerá com a captura de tela a seguir.

Screenshot that shows the Log Analytics query view.

Nota

Embora o item de telemetria bruta não contenha uma propriedade/campo de soma explícita uma vez ingerido, criamos um para você. Neste caso, tanto o como a propriedade representam a valuevalueSum mesma coisa.

Você também pode acessar sua telemetria métrica personalizada na seção Métricas do portal como uma métrica baseada em log e personalizada. A captura de tela a seguir é um exemplo de uma métrica baseada em log.

Screenshot that shows the Metrics explorer view.

Referência de métrica de cache para uso de alta taxa de transferência

Os valores métricos podem ser observados com frequência em alguns casos. Por exemplo, um serviço de alta taxa de transferência que processa 500 solicitações por segundo pode querer emitir 20 métricas de telemetria para cada solicitação. O resultado significa rastrear 10.000 valores por segundo. Nesses cenários de alta taxa de transferência, os usuários podem precisar ajudar o SDK evitando algumas pesquisas.

Por exemplo, o exemplo anterior realizou uma pesquisa de um identificador para a métrica ComputersSold e, em seguida, rastreou um valor observado de 42. Em vez disso, o identificador pode ser armazenado em cache para várias invocações de faixa:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is where the cache is stored to handle faster lookup
            Metric computersSold = _telemetryClient.GetMetric("ComputersSold");
            while (!stoppingToken.IsCancellationRequested)
            {

                computersSold.TrackValue(42);

                computersSold.TrackValue(142);

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

Além de armazenar em cache o identificador de métrica, o exemplo anterior também foi reduzido Task.Delay para 50 milissegundos para que o loop fosse executado com mais frequência. O resultado são 772 TrackValue() invocações.

Métricas multidimensionais

Os exemplos na seção anterior mostram métricas de dimensão zero. As métricas também podem ser multidimensionais. Atualmente suportamos até 10 dimensões.

Aqui está um exemplo de como criar uma métrica unidimensional:

//...

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // This is an example of a metric with a single dimension.
            // FormFactor is the name of the dimension.
            Metric computersSold= _telemetryClient.GetMetric("ComputersSold", "FormFactor");

            while (!stoppingToken.IsCancellationRequested)
            {
                // The number of arguments (dimension values)
                // must match the number of dimensions specified while GetMetric.
                // Laptop, Tablet, etc are values for the dimension "FormFactor"
                computersSold.TrackValue(42, "Laptop");
                computersSold.TrackValue(20, "Tablet");
                computersSold.TrackValue(126, "Desktop");


                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(50, stoppingToken);
            }
        }

A execução do código de exemplo por pelo menos 60 segundos resulta no envio de três itens de telemetria distintos para o Azure. Cada item representa a agregação de um dos três fatores forma. Como antes, você pode examinar mais detalhadamente na visualização Logs (Analytics ).

Screenshot that shows the Log Analytics view of multidimensional metric.

No explorador de métricas:

Screenshot that shows Custom metrics.

Observe que você não pode dividir a métrica pela nova dimensão personalizada ou exibir sua dimensão personalizada com a visualização de métricas.

Screenshot that shows splitting support.

Por padrão, as métricas multidimensionais no explorador de métricas não são ativadas nos recursos do Application Insights.

Habilite métricas multidimensionais

Para habilitar métricas multidimensionais para um recurso do Application Insights, selecione Uso e custos>estimados Métricas>personalizadas Habilitar alertas sobre dimensões>métricas personalizadas OK. Para obter mais informações, consulte Dimensões de métricas personalizadas e pré-agregação.

Depois de fazer essa alteração e enviar uma nova telemetria multidimensional, você pode selecionar Aplicar divisão.

Nota

Somente as métricas recém-enviadas depois que o recurso foi ativado no portal terão dimensões armazenadas.

Screenshot that shows applying splitting.

Visualize suas agregações métricas para cada FormFactor dimensão.

Screenshot that shows form factors.

Use MetricIdentifier quando houver mais de três dimensões

Atualmente, 10 dimensões são suportadas. Mais de três dimensões requer o uso de MetricIdentifier:

// Add "using Microsoft.ApplicationInsights.Metrics;" to use MetricIdentifier
// MetricIdentifier id = new MetricIdentifier("[metricNamespace]","[metricId],"[dim1]","[dim2]","[dim3]","[dim4]","[dim5]");
MetricIdentifier id = new MetricIdentifier("CustomMetricNamespace","ComputerSold", "FormFactor", "GraphicsCard", "MemorySpeed", "BatteryCapacity", "StorageCapacity");
Metric computersSold  = _telemetryClient.GetMetric(id);
computersSold.TrackValue(110,"Laptop", "Nvidia", "DDR4", "39Wh", "1TB");

Configuração métrica personalizada

Se quiser alterar a configuração da métrica, você deve fazer alterações no local onde a métrica é inicializada.

Nomes de dimensões especiais

As métricas não usam o contexto de telemetria do TelemetryClient usado para acessá-las. Usar nomes de dimensões especiais disponíveis como constantes na MetricDimensionNames classe é a melhor solução alternativa para essa limitação.

As agregações métricas enviadas pela métrica a seguir Special Operation Request Size não serão Context.Operation.Name definidas como Special Operation. O TrackMetric() método ou qualquer outro TrackXXX() método terá OperationName definido corretamente como Special Operation.

        //...
        TelemetryClient specialClient;
        private static int GetCurrentRequestSize()
        {
            // Do stuff
            return 1100;
        }
        int requestSize = GetCurrentRequestSize()

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                //...
                specialClient.Context.Operation.Name = "Special Operation";
                specialClient.GetMetric("Special Operation Request Size").TrackValue(requestSize);
                //...
            }
                   
        }

Nessa circunstância, use os nomes de dimensão especiais listados na MetricDimensionNames classe para especificar os TelemetryContext valores.

Por exemplo, quando a métrica agregada resultante da próxima instrução é enviada para o ponto de extremidade da nuvem do Application Insights, seu Context.Operation.Name campo de dados será definido como Special Operation:

_telemetryClient.GetMetric("Request Size", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation");

Os valores desta dimensão especial serão copiados TelemetryContext e não serão usados como uma dimensão normal . Se você quiser também manter uma dimensão de operação para exploração métrica normal, precisará criar uma dimensão separada para essa finalidade:

_telemetryClient.GetMetric("Request Size", "Operation Name", MetricDimensionNames.TelemetryContext.Operation.Name).TrackValue(requestSize, "Special Operation", "Special Operation");

Dimensionamento e limite de séries cronológicas

Para evitar que o subsistema de telemetria use acidentalmente seus recursos, você pode controlar o número máximo de séries de dados por métrica. Os limites padrão não são mais de 1.000 séries de dados totais por métrica e não mais de 100 valores diferentes por dimensão.

Importante

Use valores cardeais baixos para dimensões para evitar limitação.

No contexto da limitação de dimensões e séries temporais, usamos Metric.TrackValue(..) para garantir que os limites sejam observados. Se os limites já tiverem sido atingidos, Metric.TrackValue(..) os retornos False e o valor não serão rastreados. Caso contrário, ele retorna True. Esse comportamento é útil se os dados de uma métrica se originarem da entrada do usuário.

O MetricConfiguration construtor usa algumas opções sobre como gerenciar séries diferentes dentro da respetiva métrica e um objeto de uma implementação IMetricSeriesConfiguration de classe que especifica o comportamento de agregação para cada série individual da métrica:

var metConfig = new MetricConfiguration(seriesCountLimit: 100, valuesPerDimensionLimit:2,
                new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false));

Metric computersSold = _telemetryClient.GetMetric("ComputersSold", "Dimension1", "Dimension2", metConfig);

// Start tracking.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value1");
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value2");

// The following call gives 3rd unique value for dimension2, which is above the limit of 2.
computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3");
// The above call does not track the metric, and returns false.
  • seriesCountLimit é o número máximo de séries temporais de dados que uma métrica pode conter. Quando esse limite é atingido, as chamadas para TrackValue() isso normalmente resultariam em um retorno falsede nova série.
  • valuesPerDimensionLimit limita o número de valores distintos por dimensão de forma semelhante.
  • restrictToUInt32Values Determina se apenas valores inteiros não negativos devem ou não ser rastreados.

Eis um exemplo de como enviar uma mensagem para saber se os limites máximos são excedidos:

if (! computersSold.TrackValue(100, "Dim1Value1", "Dim2Value3"))
{
// Add "using Microsoft.ApplicationInsights.DataContract;" to use SeverityLevel.Error
_telemetryClient.TrackTrace("Metric value not tracked as value of one of the dimension exceeded the cap. Revisit the dimensions to ensure they are within the limits",
SeverityLevel.Error);
}

Próximos passos