Indice dei contenuti
Questo articolo è la terza parte di una serie di approfondimenti che illustrano come implementare un meccanismo di structured logging (registrazione strutturata degli eventi) all'interno di una tipica applicazione web realizzata con ASP.NET Core 5 e C# facendo uso di due strumenti che sfruttano le API fornite dall'interfaccia ILogger presente nel namespace Microsoft.Extensions.Logging:
- Azure Application Insights, il servizio di monitoraggio fornito da MS Azure.
- Serilog, una libreria open-source di registrazione diagnostica per applicazioni .NET disponibile su NuGet che consente di memorizzare i suddetti log sui database management system più diffusi, tra cui SQL Server e MariaDB.
Questo terzo approfondimento è dedicato a una riflessione sulle importanti differenze tra log non strutturati e log strutturati, nel corso della quale proveremo a mettere a fuoco le limitazioni dei primi e i vantaggi dei secondi.
Log non strutturati
Una caratteristica comune alla maggior parte dei logging provider messi a disposizione da .NET 5 è il fatto che registrano le informazioni all’interno di una sorta di registro: in altre parole, i log hanno l’aspetto di dati testuali che vengono visualizzati e/o memorizzati in modo non strutturato.
Questa modalità presenta indubbiamente dei vantaggi, primo tra tutti l’accessibilità: è sufficiente una console e un editor di testo per poterli visualizzare. Inoltre, poiché le registrazioni vengono memorizzate una di seguito all’altra, anche la consultazione tende ad essere abbastanza comoda, specialmente quando abbiamo bisogno di consultare le ultime “entry”.
Sfortunatamente, quando il “gioco si fa duro” queste comodità tendono a scomparire: nel momento in cui questi log raggiungono una massa critica, cosa che può accadere anche piuttosto in fretta se attiviamo dei LogLevel particolarmente verbosi, il meccanismo della “pila di log” uno di seguito all’altro recuperare le informazioni che stiamo cercando diventa sempre più difficile, scomodo e lento. Inoltre, la ricerca del dato non strutturato può portare a errori di lettura da parte degli sviluppatori o a interpretazioni errate da parte di eventuali automatismi.
Un esempio di controindicazione
Uno degli aneddoti più curiosi che rendono l’idea di quello che intendiamo dire è relativo a un’attività di debugging di un file di log non strutturato che abbiamo effettuato su un videogioco online che contava un gran numero di utenti. Gli username erano talmente tanti che qualsiasi ricerca full-text contenente le tipiche parole (“Warning”, “Error”, “Exception”) restituiva centinaia di eventi relativi a utenti che avevano quelle parole all'interno del nome: recuperavamo quindi i log relativi alla registrazione, ovvero alle attività di login e logout, di utenti come LastWarning, KingOfErrors, DeathException, e così via. Non parliamo poi della inevitabile lentezza e macchinosità di queste ricerche, visto che le registrazioni erano suddivise in tanti file generati giornalmente, ciascuno da diverse decine di megabytes.
Insomma, per farla breve, quello che manca a questo tipo di registrazioni è la possibilità di filtrarle in modo pratico attraverso uno o più parametri, come ad esempio: il tipo di log, l’ID utente, il numero di transazione, un periodo temporale con data di inizio e fine, e così via. In altre parole, dobbiamo puntare ad avere una registrazione strutturata degli eventi che consenta di poter eseguire delle query di selezione. Un modo semplice per ottenere questo risultato può essere quello di memorizzare i log in un formato strutturato, come ad esempio XML o JSON; ma questo approccio richiederebbe comunque l’utilizzo di un software che consenta di leggere questi formati e applicare filtri o aggregazioni, e non sarebbe comunque esente dai problemi di performance di cui abbiamo parlato sopra.
Per questo motivo, un approccio decisamente più comodo può essere quello di scrivere queste registrazioni direttamente all’interno di una base dati, possibilmente analoga a quella utilizzata dalla nostra applicazione: un DBMS come Microsoft SQL Server o MariaDB. In alternativa, è possibile utilizzare strumenti di terze parti che consentono comunque una registrazione dei suddetti eventi in formato strutturato, come quelli forniti dal servizio Application Insights di MS Azure.
Log strutturati
Registrando i nostri log applicativi all'interno di un database o di un servizio che consenta la memorizzazione strutturata potremo contare su diversi vantaggi, come ad esempio:
- Nessun bisogno di installare strumenti per leggere i log in modalità manuale.
- Nessun bisogno di scrivere codice per leggere i log in modalità automatica (es. da applicativi di controllo o manutenzione).
- Possibilità di filtrare i risultati per singoli campi o aggregazioni di campi, anche esterni alla tabella relativa ai log: ad esempio, potremmo fare una JOIN con gli utenti relativi a determinate tipologie di log, così da raggruppare insieme dati utente e informazioni utili per il debug.
- Possibilità di estrarre i log in vari modi, evidenziando le informazioni salienti e omettendo quelle che è bene non inviare.
- Ottimizzazione delle performance, grazie all’utilizzo delle funzionalità di indicizzazione del DBMS che consentono di gestire in modo efficiente anche un gran numero di record.
… e così via. Come si può vedere, si tratta di aspetti che consentono di risolvere molti dei nodi che erano venuti al pettine quando abbiamo messo a fuoco le limitazioni log non strutturati.
Come registrare log strutturati
Ad oggi, le possibilità più semplici per registrare log in modo strutturato utilizzando l’interfaccia ILogger fornita da .NET 5 sono le seguenti:
- Utilizzare l’Azure Application Insights Logging Provider, che consente di registrare i log sull’apposito servizio di monitoring fornito da MS Azure.
- Utilizzare una libreria di terze parti che consenta di scrivere i suddetti log all’interno di un DBMS come SQL Server e MariaDB, ma anche altre basi di dati relazionali e non relazionali come MySQL, MongoDB, Azure CosmosDB, CouchBase, Amazon DynamoDB, e così via.
Nei prossimi articoli vedremo come è possibile configurare la nostra app di esempio per consentire la registrazione dei log con ciascuna di queste modalità.
Conclusioni
Per il momento è tutto: nel prossimo articolo vedremo come registrare log in modo strutturato utilizzando l’interfaccia ILogger fornita da .NET 5 tramite Azure Application Insights, il servizio di monitoraggio fornito da MS Azure, e Serilog, una libreria open-source di registrazione diagnostica per applicazioni .NET disponibile su NuGet che consente di memorizzare i suddetti log sui database management system più diffusi, tra cui SQL Server e MariaDB.
Articoli correlati
- Indice degli argomenti
- ASP.NET Core 5 Application Logging: concetti di base
- Application Logging in .NET 5: Logging Provider predefiniti
- Differenze tra Log strutturati e non strutturati
- Structured Logging con Azure Application Insights
- Structured Logging su DBMS con Serilog