Jump to content

Recommended Posts

Guest wdossantos
Posted

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.

 

 

 

1*QoVJc2h3fYADEeCw-qp2nA.webp

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.

 

 

 

1*0zcQ2QZVf_371pKmSsK4Xw.webp

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.

 

1*okcITvn0YQjxCiq7-RLz6w.webp

Transaction search ultimas 24 horas

 

 

 

 

 

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

 

1*cnmja9JiWQ8zStbrsWKGHQ.webp

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)

 

1*mv4pkVqvV-HBpqS-g5z7Qw.webp

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

1*T57ZFZQnxIVeqNfkzEnTvg.webp

_ViewImports.cshtml com a instrução acima no Visual Studio 2019

 

 

no arquivo _Layout.cshtml

 

 

 

@Html.Raw(JavaScriptSnippet.FullScript)

1*gT77fzEjqb-3krXhkCt4Sg.webp

_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.

 

 

 

1*LKy_eWw0GdXbZvvks5Um4A.webp

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

 

1*fbyIxeWhdCb2Mn9fpE6khg.webp

Transaction Search com requisições

 

 

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

 

1*LKy_eWw0GdXbZvvks5Um4A.webp

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("wilsonsantosnet - Overview").Result;

telemetryClient.TrackEvent("Chamada wilsonsantosnet - Overview 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.

 

1*f5Pys8w1BUJO72C2c6pRhQ.webp

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.

 

 

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. Visão geral do Application Insights - Azure Monitor
  2. Azure Application Insights para aplicativos ASP.NET Core — Azure Monitor | Microsoft Docs
  3. Configurar o monitoramento para o ASP.NET com o Azure Application Insights - Azure Monitor
  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

 

Continue reading...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...