In questo articolo affrontiamo l‘argomento della gestione del logging nelle applicazioni enterprise cercando di illustrare alcuni aspetti della problematica. Vedremo velocemente i concetti di base e presenteremo l‘utilizzo degli strumenti standard, indicando qualche punto cui fare particolarmente attenzione.
Introduzione
In questo articolo affrontiamo un altro aspetto, quello del logging, che come quello della gestione delle eccezioni è spesso trascurato nella scrittura delle applicazioni.
Purtroppo molto spesso in fase di progettazione di una applicazione l’aspetto legato al logging è sovente trascurato per ragioni di tempo ma anche perche’ non si ritiene di dover dedicare risorse a questo che sembra un task secondario. Allo stesso modo gli sviluppatori tendono a non prestare l’attenzione necessaria alla scrittura delle istruzioni di logging in quanto concentrati sugli aspetti core del proprio sviluppo.
Purtroppo però soprattutto in caso di debugging di problemi la mancanza di una gestione corretta del logging applicativo porta a notevoli problemi.
Non esiste ovviamente ne’ un approccio ne’ uno strumento unico per affrontare questo problema ma si possono però illustrare alcune strade che aiutino nella scelta dell’approccio corretto.
Aspetti di base
Per realizzare il logging della propria applicazione, la prima possibilità è quella di utilizzare un approccio artigianale o fatto in casa. Si potrebbe pensare di costruirsi una propria classe o una propria libreria di classi che assolva al compito di “loggare” l’applicazione.
Questo approccio è fortemente sconsigliato per ovvi motivi: per il tempo di sviluppo che richiede, per la difficoltà di arrivare ad una implementazione valida e, soprattutto, per la disponibilità di framework di logging ormai in uso comune da anni da parte della comunità di sviluppatori J2EE.
Le possibilità oggi sono molteplici ma sicuramente tra le soluzioni valide vanno citate Java Logging API, presente dalla versione di Java 1.4, e Apache Log4J, il framework open-source più utilizzato in assoluto per il logging delle applicazioni.
Entrambi i prodotti hanno una struttura comune che prevede l’utilizzo di un oggetto logger al quale viene fornito il messaggio di logging da generare in base ad una priorità predefinita. Il layout del messaggio e la destinazione finale dello stesso è separata dalla generazione e viene gestita da opportune classi che si occupano di formattare il messaggio e di inviarlo alla destinazione opportuna.
Nella figura presente in [1] e riportata di seguito vi è una raffigurazione dei principali componenti logici del framework di logging.
Figura 1 – Componenti per il logging
Questa struttura consente una notevole flessibilità in quanto distingue la fase di generazione del messaggio dalla fase di formattazione e di invio alla destinazione finale che può essere la console di sistema, un file, una e-mail , un socket o qualsiasi altra destinazione si desideri.
Il Log4j è un’ottima implementazione perche’ prevede molte possibilità di generazione di layout differenti e prevede molteplici appender per destinazioni più disparate.
Anche a livello di scrittura del codice il Log4J è estremamente semplice da utilizzare; è sufficiente definire un logger e generare il messaggio di logging con la priorità desiderata.
Di seguito sono riportate le semplici righe di codice che consentono di inserire le istruzioni di logging nella classe desiderata:
package it.mokabyte.logging.* import org.apache.log4j.Logger; public class ClasseEsempio { private static final Logger logger = Logger.getLogger(ClasseEsempio.class.getName()); ... ... public void metodoEsempio() { ... if (logger.isDebugEnabled()) { logger.debug("Esecuzione metodo di esempio"); } ... } }
La configurazione del layout e della destinazione è effettuata a parte e preferibilmente esternamente al codice in file properties o file XML in modo che possa essere modificata senza dover effettuare modifiche e ricompilazioni (concetto tanto semplice e diffuso, quanto importante e risolutivo).
Di seguito è riportato un esempio di file di configurazione che imposta la scrittura su un file di testo di dimensione massima di 5Mb del quale viene effettuato il rolling per un numero massimo di 10 volte e secondo un layout predefinito:
value="%d %-5r %-5p [%c] (%t:%x) %m%n" />
Ovviamente questa è solo una delle innumerevoli possibilità. Per un panorama completo delle possibilità si consiglia di approfondire mediante la guida del framework [2].
Scelte per un logging corretto
A parte la scelta dello strumento, per effettuare il logging è molto importante avere una strategia giusta. È vero che già di per se’ Log4j è un ottimo strumento; ma anche con questo, se non si scelgono le modalità corrette, si può arrivare a risultati scadenti.
Una prima scelta fondamentale è definire con accuratezza il livello di logging delle istruzioni da inserire nel codice. In genere i framework come Log4J consentono di assegnare una priorità ai messaggi di logging: tale priorità varia in genere tra alcuni livelli abbastanza standardizzati. Vediamoli brevemente di seguito.
warning
Sono messaggi che devono indicare situazioni che potenzialmente possono portare ad errori
info
Messaggi che danno informazioni sul sistema ma che non arrivano a un livello di dettaglio approfondito
debug
messaggi utilizzati in genere per effettuare debugging di errori e quindi a un elevato livello di dettaglio
error
messaggi conseguenti a errori irrecuperabili verificatisi nel sistema
È molto importante scegliere nella scrittura del codice di logging il livello adeguato a seconda dei casi in modo da ottenere un logging più o meno verboso. Ad esempio avendo predisposto opportune istruzioni di debugging abilitando il livello corrispondente nella configurazione, si potrà ottenere un logging molto dettagliato importantissimo per la risoluzione di problemi. Attivando invece un livello di logging a una verbosità minore si potrà comunque monitorare lo stato dell’applicazione, ma senza ottenere file di log eccessivamente grandi e, soprattutto, lunghi e difficili da leggere. Questo, ad esempio, può essere fatto in un ambiente di produzione nel quale un livello di logging molto dettagliato verrà attivato solo in casi di necessità particolari conseguenti a malfunzionamenti dei quali non si riesca a determinare la causa.
Altra scelta importante dopo aver scelto uno strumento e il livello opportuno di logging è quella di selezionare cosa loggare nell’applicazione. Questa scelta non è semplice perche’ si rischia sempre o di esagerare (e inserire kilometri di righe di logging) o di inserirne troppo poche (e quindi avere un logging praticamente inutile). Dare consigli in questo senso non è semplice perche’ dipende dall’applicazione, se è distribuita o meno, dalla complessità del codice e da altri fattori.
Logging indispensabile
Alcune operazioni sono comunque consigliate in generale come ad esempio loggare le eccezioni e lo stack-trace generato. Questo consente di tenere traccia nel proprio log delle situazioni di errore e di individuarne le cause in modo più semplice. Altra cosa molto importante è inserire istruzioni di tipo informativo all’inizio e alla fine di ogni metodo. Ciò può sembrare abbastanza inutile, ma in realtà, specialmente nei sistemi distribuiti o realizzati secondo una struttura a servizi, può essere molto utile capire quali siano i metodi invocati e se una chiamata a una classe di implementazione di un web service sia stata ricevuta o meno.
Altra scelta che si può rivelare utile è quella di loggare, magari solo a un livello di debug, i parametri di input/output dei metodi o i valori di alcune variabili cruciali per la logica applicativa implementata. Questo spesso è molto utile per capire un comportamento anomalo nel software.
Infine, ed è molto importante in un ambiente multithread tipico delle applicazioni enterprise, occorre poter inserire informazioni contestuali al thread stesso e distinguere così tra le varie le richieste concorrenti.
Questo è possibile con il Log4J utilizzando un filtro che intercetti le richieste in arrivo verso la propria applicazione e inserisca le informazioni desiderate nel Nested Diagnostic Context del thread [2].
Ulteriori sviluppi del logging
Una possibilità che oggi si ha per le operazioni di logging è anche quella di utilizzare la programmazione ad aspetti (Aspect Oriented Programming, AOP) che trova nel logging una delle sue applicazioni naturali poiche’ si tratta di un aspetto trasversale ad una intera applicazione. Sarebbe difficile parlare in due righe di AOP e di come implementare il logging con un framework ad aspetti: ci proponiamo di farlo eventualmente in un articolo dedicato.
Conclusioni
Nel presente articolo abbiamo trattato l’argomento del logging delle applicazioni. Un argomento di questo tipo così generico e dagli innumerevoli aspetti non può essere trattato in poche righe quindi ovviamente si sono enunciati solo pochi aspetti di base. L’obiettivo era quello di fornire uno spunto soprattutto per sensibilizzare su questa tematica e per far comprendere come una corretta strutturazione delle operazioni di logging può portare a notevoli benefici nello sviluppo e soprattutto nella manutenzione di un applicazione.
Riferimenti
[1] Charles Chan, “Effective logging practices ease enterprise development”, developerWorks, agosto 2005
http://www.ibm.com/developerworks/java/library/j-logging/
[2] Ceki Gulcu, “The Complete Log4j Manual”, QOS.ch, 2003