Tracciare il body delle richieste fallite con Application Insights in .NET Core

di Cristian Civera, in Application Insights,

Quando vogliamo sapere cosa succede nel nostro applicativo web, possiamo far ricorso ad Application Insights. Installando l'SDK otteniamo il tracciamento di tutte le richieste, gli errori e ci vengono fornite metriche utili.

Tra le richieste ci ritroviamo anche il relativo esito e può sicuramente capitare di restituire uno status code fallito, come il 400 (bad request). In queste situazioni non troviamo molti dettagli, perché non si è verificato un errore e non vediamo alcun messaggio, ma comunque la richiesta da un punto di vista web è fallita.

Per ovviare a questo problema possiamo pensare di arricchire le informazioni memorizzate. La tecnica migliore per farlo consiste nel creare una classe di tipo ITelemetryInitializer, ma purtroppo lavora in sincrono e non ci permette di accedere a tutte le informazioni necessarie. In questo script quindi proponiamo l'uso di un middleware che si ponga all'inizio e alla fine delle richieste, arricchendo la telemetria.

Partiamo quindi dal preparare lo scheletro del middleware, con costruttore e metodo Invoke.

public class BadRequestMiddleware
{
    private readonly RequestDelegate _next;

    public BadRequestMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {      
    }
}

All'interno di Invoke dobbiamo decidere per quali operazioni tracciare maggiori dettagli. Nel nostro esempio identifichiamo richieste in JSON per le quali dobbiamo abilitare il buffering della richiesta. Questa funzionalità è normalmente spenta, per rendere il più leggero possibile l'esecuzione delle richieste, ma abilitandola ci permette, in caso di esito negativo nella nostra risposta, di leggere l'intero body e aggiungerlo alla telemetria, come mostrato nel codice seguente.

bool isJson = httpContext.Request.ContentType == "application/json";
// Solo per le richieste di tipo JSON
if (isJson)
{
    httpContext.Request.EnableBuffering();
}

// Chiamo il resto della pipeline
await _next(httpContext);

// In caso di 400
if (isJson
    && httpContext.Response.StatusCode == 400
    && httpContext.Features.Get<RequestTelemetry>() is RequestTelemetry requestTelemetry)
{
    // Rileggo il body
    httpContext.Request.Body.Position = 0;
    string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();

    // Imposto la proprietà
    requestTelemetry.Properties["Request"] = body;
}

Dopo aver attivato il buffering proseguiamo con l'invocazione classica del resto della pipeline. Successivamente, in caso di richiesta JSON, con risposta 400 e con la telemetria presente, andiamo a rileggere il body come stringa e lo aggiungiamo alle proprietà. In background il motore di Application Insights si occuperà della registrazione della richiesta comprensivo della nostra proprietà.
Non ci resta che attivare il middleware nello Startup attraverso la registrazione seguente:

app.UseMiddleware<BadRequestMiddleware>();

Fatto questo nel portale ogni volta che troviamo una risposta di tipo 400 troviamo tra le custom properties anche il JSON.

Bisogna prestare attenzione a questa funzionalità, perché l'utilizzo del buffering va ad appesantire il nostro applicativo. E' fondamentale quindi cercare di attivarlo solo al minor numero di richieste possibili.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi