monitoraggio attività

in ASPNET Core, Informatica

Monitoraggio Integrità – ASPNET Core

Reading Time: 3 minutes

Spesso si ha la necessità di implemetare applicazioni che effettuano il monitoraggio di server, o di servizi presenti all’interno di un infrastruttura. In particolare, può risultare molto utile realizzare applicazioni che consentano di ottenere informazioni, quasi in tempo reale, su servizi e microservizi.

Il framework DotNet Core mette a disposizione, a partire dalla versione 2.2 il package Microsoft.AspNetCore.Diagnostics.HealthChecks che ha ricevuto una serie di aggiornamenti piuttosto consistenti nella release 3.0. Questo package è stato implementato con lo scopo di implementare un servizio di monitoring per controllare lo stato di altri servizi: ad esempio monitorare lo stato di un server web.

Attivazione del middleware

L’attivazione della funzionalità passa dall’attivazione di un middleware all’interno della nostra applicazione ASPNet Core. Il middleware da aggiungere è HealthChecks.

Come per tutti i middleware che si vogliono aggiungere è necessario modificare il file Startup.cs nel metodo ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
           services.AddControllersWithViews();
           // In production, the Angular files will be served
           // from this directory
           services.AddSpaStaticFiles(configuration =>
           {
                configuration.RootPath = "ClientApp/dist";
           });
           services.AddHealthChecks();
}

aggiungendo il middleware tramite services.AddHealthChecks(). A questo punto è necessario procedere con la configurazione all’interno del metodo Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRouting();

app.UseHealthChecks("/hc");

app.UseEndpoints(endpoints =>
  {
    endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
  });
}

L’attivazione del middleware avviene specificando la route che dovrà essere utilizzata come endpoint: nel nostro caso /hc definita tramite app.UseHealthChecks(“/hc”). Inoltre, il middleware è stato posizionano prima della definizione delle route di default, in modo da non pregiudicarne il normale funzionamento.

Mandando in esecuzione l’applicazione possiamo subito verificare il funzionamento del nuovo middleware, digitando http://localhost:port/hc. Ovviamente è necessario sostituire port con la porta su cui la nostra applicazione sarà in esecuzione. Se tutto sarà andato a buon fine, verrà caricata una nuova pagina:

che visualizzerà la dicitura Healty, ad indicare che il middleware sta funzionanndo correttamente. Il prossimo passo sarà quello di monitorare qualche servizio in rete.

Aggiungere il monitoring

Proviamo ad implementare un semplice controllo di un host remoto tramite un semplice ping verso l’indirizzo ip. Per prima cosa è necessario identificare gli stati della risorsa che vogliamo gestire. In particolare il ping consideriamo:

  • Healthy: quando il ping risponde con successo e senza timeout
  • Degraded: quando il ping risponde con successo ma il round-trip-time è troppo alto
  • Unhealthy: quando il ping non risponde

A questo punto, dopo aver definito i 3 stati possibili, possiamo procedere con la creazione della classe che si occuperà di verificare l’health del nostro servizio. La classe si chiamerà ICMPHealthCheck, che dovrà ereditare da IHealthCheck.

using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
namespace HealthCheck
{
public class ICMPHealthCheck : IHealthCheck
{
   private string Host = "www.does-not-exist.com";
   private int Timeout = 300;
   public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext 
   context, CancellationToken cancellationToken = default)
   {
    try
     {
       using (var ping = new Ping())
       {         
         var reply = await ping.SendPingAsync(Host);
         switch (reply.Status)
          {
            case IPStatus.Success:
            return (reply.RoundtripTime > Timeout)
              ? HealthCheckResult.Degraded()
              : HealthCheckResult.Healthy();
            default:
            return HealthCheckResult.Unhealthy();
         }
        }
       }
      catch (Exception e)
      {
        return HealthCheckResult.Unhealthy();
      }
   }
 }
}

La classe dovrà implementare il metodo CheckHealthAsync che si occuperà di effettuare i test tramite il comando ping . All’interno di reply troveremo le informazioni della risposta del ping, e potremo ritornare lo stato della risposta.

Attivare il controllo

A questo punto possiamo attivare il check nella configurazione del middleware (all’interno di Startup.cs):

public void ConfigureServices(IServiceCollection services)
{
       //...
       services.AddHealthChecks()
      .AddCheck<ICMPHealthCheck>("ICMP");
       //...
}

A questo punto accendo all’endpoint (“/hc”) riceveremo il messaggio:

il motivo è molto semplice, viene fatto il ping su un host che non esiste. Il nome dell’host è inserito direttamente all’interno della classe HealthCheck.

Fino a qui abbiamo realizzato un semplice controllo legato al ping di un server remoto. La nostra implementazione presenza almeno tre lacune:

  • il nome dell’host da verificare e la soglia del timeout dovrebbe essere passata come parametro
  • la tipologia di messaggio che viene ritornata (Healthy and Unhealthy) risulta un pò troppo sintetico. Sarebbe meglio ottenere anche un messaggio un pò più dettagliato
  • la risposta che viene ritornata è di tipo testo, se vogliamo integrare il servizio per l’accesso remoto (es. da un applicazione angular) sarebbe meglio inviare un messaggio in formato json

Nel prossimo post estenderemo le funzionalità della nostra classe checker per risolvere i problemi precedenti.