Application Insights

This post has been republished via RSS; it originally appeared at: Microsoft Tech Community - Latest Blogs - .

Não se pode gerenciar o que não se pode medir

 

A ideia é compartilhar algumas situações que já passei para instrumentar uma aplicação utilizando o recurso Application Insights, é verdade que está cada vez mais fácil de se fazer isso, principalmente nas últimas versões do .NET Core, no entanto existem cenários onde um pouco de ajuda pode poupar dias de tentativas e erros.

 

O que é o Application Insights?

 

O Application Insights é uma ferramenta de APM (Application Performance Management), produto de monitoração de aplicações que fica dentro de um produto maior chamado Azure Monitor, solução mais abrangente para coleta, análise e ação com base na telemetria em seus ambientes de nuvem e on-premisses que ajuda a identificar de maneira proativa o desempenho de seus aplicativos e suas dependências.

 

Diagrama Azure Monitor

Utilizar o Application Insights é uma tarefa relativamente simples principalmente quando estamos com as ultimas versões do .NET, mas temos cenários complicados, como no caso de utilização de proxy, e de plataformas mais antigas que pretendo cobrir aqui. Quando estamos no .NET Core basta instalar um SDK, em uma aplicação web, vamos usar esse pacote:

Install-Package Microsoft.ApplicationInsights.AspNetCore

O pacote pode variar de acordo com a plataforma que você estiver trabalhando, dê uma olhada aqui, vou mostrar a maior parte dos exemplos no .NET Core, mas no final do artigo eu mostro as diferenças para full framework e para windows services e consoles.

Depois você obtém a chave de instrumentação no Azure ou a connection string, e configura essa chave na sua aplicação.

 

.NET Core

 

Para .NET Core devemos fazer algo como isso na classe startup no método ConfigureServices:

services.AddApplicationInsightsTelemetry();

e no appsettings.json

"ApplicationInsights": {  
    "ConnectionString": "..."  
  },

Também podemos configurar nossa aplicação para direcionar os logs para o Application Insights

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.ApplicationInsights;

namespace AppInsigths
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.ConfigureLogging(
                        (context, builder) =>
                        {
                            builder.AddApplicationInsights(context.Configuration["ApplicationInsights:InstrumentationKey"]);
                            builder.AddFilter<ApplicationInsightsLoggerProvider>("Geral", LogLevel.Information);
                        });
                });
    }
}

Vou Criar uma Controller Simples para enviar algumas informações de logs e telemetria

using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AppInsigths.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {

        private readonly ILogger _logger;
        private TelemetryClient _telemetry;
        public WeatherForecastController(ILogger<WeatherForecastController> logger, TelemetryClient telemetry)
        {
            _logger = logger;
            _telemetry = telemetry;
        }

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            _telemetry.TrackEvent("WinGame");
            _logger.LogWarning("An example of a Warning trace..");
            _logger.LogError("An example of an Error level message");

            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

 

Já podemos ver esses dados em ferramentas do Application Insights como Application Map, Live Metrics e Transaction Search.

 

Tela do application insights com a ferramenta de LiveMetrics aberta

 

 

Os dados de trackEvent ficam na tabela de log do customEvents e os dados de logs ficam na tabela de traces

no TrackTrace podemos definir o nível de severidade do trace, já o TrackEvent usamos para analisar a frequência com que um método é chamado.

 

 

Transaction Search

 

Uma ferramenta que eu gosto muito do Application Insights é o Transaction Search ela permite fazer buscas apenas por palavras chaves facilitando a busca por requisições especificas.

Transaction search ultimas 24 horas

 

 

Mas também podemos usar os filtros da ferramenta para refinar a busca

Transaction search filtros

E o melhor é que podemos ver como fica consulta clicando em View in Logs, assim sabemos em quais tabelas os dados se encontram, podemos fazer modificações e aprender como funciona o KQL (Kusto Query Language)

Logs consultas

 

RoleName

 

Essa é uma forma de usar a mesma instância do Application Insights para várias aplicações diferentes e conseguir organizar os dados em espaços delimitados.

 

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;

namespace AppInsigths
{
    public class CustomTelemetryInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {
            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
            {
                //set custom role name here
                telemetry.Context.Cloud.RoleName = "AppInsigths";
            }
        }
    }
}

Precisa configurar na classe startup no método ConfigureServices:

 

services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();

 

Capturando dados no navegador em aplicações ASP.NET Core

 

no arquivo _ViewImports.cshtml adicione

 

@inject Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet JavaScriptSnippet
_ViewImports.cshtml com a instrução acima no Visual Studio 2019

no arquivo _Layout.cshtml

 

@Html.Raw(JavaScriptSnippet.FullScript)
_Layout.cshtml com a instrução acima no Visual Studio 2019

 

.NET Full framework (ASP.NET)

 

No Full framework, temos diversas particularidades é muito importante consultar a documentação oficial, aqui vou mostrar os cenários que eu já passei, e nesse caso estou falando de algumas versões da família 4.X

Podemos usar aquele esquema automático no Visual studio 2019, botão direito no projeto e Clicar em Configurar Application Insights, mas eu instalei os pacotes na mão mesmo usando nuget console:

 

Install-Package Microsoft.ApplicationInsights.Web

 

Esse pacote adicionou um monte de dependências, modificou meu webconfig com os httpModules necessários, além de ter criado o arquivo ApplicationInsights.config. Caso ele não tenha sido criado acesse o modelo aqui

Depois peguei a Connection String direto do portal do Azure, no recurso do application insights escolhido, criado especificamente para a minha aplicação.

 

portal do azure connection string

colei no arquivo ApplicationInsights.config, algo como isso, fica abaixo da sessão TelemetrySinks.

<ConnectionString>InstrumentationKey=d42120e4-dc8a-4b06-9193-5eb905de8039;IngestionEndpoint=https://centralus-2.in.applicationinsights.azure.com/;LiveEndpoint=https://centralus.livediagnostics.monitor.azure.com/</ConnectionString>

pronto já temos requisições

Transaction Search com requisições

O deploy foi feito no AppServices do azure que está configurado com o menu Application Insights habilitado:

app services appinsightsFF | Application Insights habilitado

 

Windows Services

 

Segui o mesmo esquema, instalei os pacotes manualmente pelo nuget console, só que aqui instalei apenas:

 

Install-Package Microsoft.ApplicationInsights.WindowsServer

Tudo foi criado automaticamente o aquivo ApplicationInsights.config, mas aqui não tem webconfig, e precisamos fazer algumas implementações.

No arquivo principal do windows services, a classe que herda de ServiceBase no método OnStart usei essa implementação

 

protected override void OnStart(string[] args)  
{  
    var text =  $"Service Start At {DateTime.Now}";  
    TelemetryConfiguration.Active.TelemetryInitializers.Add(new CloudRoleNameTelemetryInitializer());  
    var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);  
    telemetryClient.TrackEvent(text);  
  
}

 

Usando a classe TelemetryConfiguration inicializei a Rolename, configurei a classe TelemetryClient e com ela começo a logar informações por exemplo usando o método TrackEvent, tem algo parecido no onStop

 

protected override void OnStop()  
{  
    var text = $"Service Stop At {DateTime.Now}";  
    var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);  
    telemetryClient.TrackEvent(text);  
  
}

 

é isso mesmo, aqui eu sou responsável por definir os pontos da implementação onde quero guardar alguma informação, e para isso usei uma instância da classe TelemetryClient com o método TrackEvent

mas observei um trace estranho:

 

AI: error collecting 3 of the configured performance counters. Please check the configuration.

 

Ele não interfere na captura dos eventos, mas incomoda um pouco, olhando a documentação sobre application insights para console, percebo que o arquivo ApplicationInsights.config é muito mais simples e não precisa da tag a seguir.

 

<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.PerformanceCollectorModule, Microsoft.AI.PerfCounterCollector">
    ...
</Add>

 

Basta comentá-la e o erro não será logado.

Também percebi que nenhum stop foi pego, então adicionei um sleep logo depois de enviar o TrackEvent do stop e um flush:

 

telemetryClient.Flush();  
System.Threading.Thread.Sleep(1000);

 

Console Application

 

Fiz um teste com uma aplicação console também, e segui a mesma linha do Windows Service, porém usei outro pacote:

 

Install-Package Microsoft.ApplicationInsights.WorkerService

aparentemente teve o mesmo efeito do windowsService, também criou o arquivo ApplicationInsights.config.

Fiz as mesmas inicializações que o windows services, mas coloquei um implementação para poder capturar requisições https.

 

static void Main(string[] args)  
  {  
      TelemetryConfiguration.Active.TelemetryInitializers.Add(new CloudRoleNameTelemetryInitializer());  
      var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);  
  
  
      telemetryClient.TrackTrace($"Start at {DateTime.Now} por TrackTrace");  
      telemetryClient.TrackEvent($"Start at {DateTime.Now} por TrackEvent");  
  
      var httpClient = new HttpClient();  
      using (telemetryClient.StartOperation<RequestTelemetry>("ConsoleAppI2"))  
      {  
          var res = httpClient.GetAsync("https://github.com/wilsonsantosnet").Result;  
          telemetryClient.TrackEvent("Chamada https://github.com/wilsonsantosnet pronta");  
      }  
      Console.Read();  
  
  }

O erro de coleta observado no windows service também ocorreu.

 

AI: Error collecting 3 of the configured performance counters. Please check the configuration.

Basta ajustar o arquivo ApplicationInsights.config conforme acima.

podemos ver diferentes tipos de coletas visualizadas pelo Transaction Search

 

O Problema do Proxy

 

O Application Insights usa a classe HttpClient para enviar as informações para o Azure, mas em alguns casos as aplicações podem estar em uma intranet que não tem acesso a internet, por isso precisamos definir um proxy global na aplicação e assim o tráfego vai ser direcionado para esse endereço.

A questão é que o HttpClient funciona como uma faced, pode usar outras classes para fazer as chamadas de acordo com a plataforma.

O HttpClient é uma API de alto nível que encapsula a funcionalidade de nível inferior disponível em cada plataforma em que é executada.

Portanto em uma aplicação .NET Core usamos a seguinte configuração para globalmente configurar um proxy

 

var proxy = new WebProxy();  
Configuration.Bind("DefaultProxy", proxy);  
HttpClient.DefaultProxy = proxy;

..NET Core 2.x não permite configuração de proxy na aplicação exceto por código.

No entanto o método DefaultProxy não está disponível em uma aplicação Full Framework, mas como sabemos graças a documentação acima, por baixo dos panos a classe usada será a HttpWebRequest

Portanto podemos fazer algo assim em aplicações cuja classe HttpClient seja provida pelo Full Framework

 

var proxy = new WebProxy();  
Configuration.Bind("DefaultProxy", proxy);  
HttpWebRequest.DefaultWebProxy = proxy;

 

Variáveis de ambiente

 

A partir do .NET Core 3.1 é possível configurar o proxy usando variáveis de ambiente.

  1. HTTP_PROXY Define o proxy que usará o protocolo HTTP.
  2. HTTPS_PROXY Define o proxy que usará o protocolo HTTPS.
  3. ALL_PROXY Define o proxy que será usado caso HTTP_PROXY e HTTPS_PROXY não seja definido.
  4. NO_PROXY Define endereços que não farão o uso do servidor Proxy

Estas variáveis serão do tipo System, para que todos os processos em execução tenham acesso ao seu conteúdo, não somente o usuário logado. Outro ponto importante destacar é que das aplicações desenvolvidas com .NET Framework ou .NET Core, somente as com suporte ao .NET Core 3.X será influenciada por elas, as demais versões (exemplo versão 4.X ou versão anterior do .NET Core) não serão afetadas.

 

Arquivos de Configuração

 

Também podemos apenas fazer essa configuração nos arquivos de configuração da aplicação de acordo com a plataforma;

 

.NET Core appsettings.json

 

"DefaultProxy": {  
    "Address": url,  
    "BypassProxyOnLocal": "true",  
    "BypassList": \[  
      http://\*\\.dominio\\.subdominio\\.br/  
      \]  
  }

 

Full framework web.config / app.config

 

<system.net>  
    <defaultProxy enabled="true" useDefaultCredentials="true">  
      <proxy proxyaddress="url" bypassonlocal="True" usesystemdefault="True"/>  
      <bypasslist>  
        <add address=".+\\.url.\*$"/>  
      </bypasslist>  
    </defaultProxy>  
  </system.net>

 

Troubleshoot logs

 

Uma dica que pode nos ajudar muito a entender o que esta acontecendo por baixo do capo é habilitar os logs do Application Insights, para isso basta alterar o ApplicationInsights.config

<TelemetryModules>  
  <Add Type="Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.FileDiagnosticsTelemetryModule, Microsoft.ApplicationInsights">  
    <Severity>Verbose</Severity>  
    <LogFileName>mylog.txt</LogFileName>  
    <LogFilePath>C:\\\\SDKLOGS</LogFilePath>  
  </Add>  
</TelemetryModules>

 

Conclusão

 

Podemos ver que no geral não é um processo de configuração complicado. Os benefícios de poder ver as informações de log em uma ferramenta centralizada e com diversos recursos que ajudam na análise, visualização e disponibilização dessas informações são enormes.

 

Referência

 

  1. https://learn.microsoft.com/pt-br/azure/azure-monitor/app/platforms
  2. Azure Application Insights para aplicativos ASP.NET Core — Azure Monitor | Microsoft Docs
  3. https://learn.microsoft.com/pt-br/azure/azure-monitor/app/asp-net
  4. https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-troubleshoot-no-data
  5. Troubleshoot no data in Application Insights for .NET — Azure | Microsoft Learn

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.