Il modulo logging di Python: come individuare gli errori di script

Python è un linguaggio di programmazione orientato agli oggetti molto diffuso. Molti sviluppatori apprezzano Python perché questo linguaggio di scripting permette di sviluppare programmi più velocemente rispetto ai linguaggi di compilazione come Java. Rispetto ai linguaggi di programmazione procedurali "tradizionali" come Perl, Python ha il vantaggio di essere facile da leggere e da mantenere. Che si tratti di intelligenza artificiale, interfaccia utente grafica o amministrazione di sistema: Python può essere utilizzato per una varietà di compiti. Ma più si utilizza un linguaggio di programmazione, più diventa importante adottare una buona cultura dell'errore. Il logging dovrebbe avvenire sin dalla prima fase di sviluppo fino all'uso effettivo da parte dell'utente.

Nella libreria Python trovate un pratico modulo di logging. Sia per il semplice debug che per il logging centrale da server diversi, questo modulo di logging Python può rendere il lavoro degli sviluppatori e degli operatori molto più semplice.

Che cos'è il logging?

Il termine "logging" deriva dalla parola inglese "log" e si riferisce, in questo contesto, a un protocollo. Simile a un diario di bordo, contiene tutti i record importanti di un evento. A seconda di ciò che deve essere esaminato, vengono registrate solo alcune oppure tutte le azioni (o eventi) di un processo.

Quando si impara un nuovo linguaggio di programmazione è normale commettere degli errori. Anche se Python è comprensibile per chi conosce già linguaggi di programmazione come C++ o Java, grazie alla similitudine delle strutture (ad esempio la forma dei loop), ogni linguaggio ha le sue peculiarità. Python, ad esempio, rappresenta le gerarchie mediante rientri. Anche il funzionamento dell'applicazione più semplice sarà compromessa se per sbaglio viene omesso uno spazio. Un log degli errori indica agli sviluppatori inesperti durante il debug la riga corrispondente e l'errore "unexpected Indentation". In questo caso, Python logging registra semplici errori di script e mostra un messaggio. Ma questo non è tutto. Gli sviluppatori utilizzano il logging nei programmi per i compiti più disparati:

  • Debug: l'intero codice sorgente viene controllato per verificare la presenza di errori e assicurare che il programma finito funzioni senza problemi.
  • Individuazione e correzione delle lacune di sicurezza: i possibili rischi vengono identificati ed eliminati preventivamente.
  • Informatica forense: può essere utilizzata per determinare la causa di eventi critici, come gli attacchi hacker, mediante il file di log.
  • IT Auditing: mediante questo audit si determina se la sicurezza e l'integrità dei dati sono garantite, si confrontano gli obiettivi aziendali con le strutture informatiche esistenti per la loro compatibilità e si analizza l'efficienza dei programmi e dei sistemi operativi.
  • Confronto tra diverse versionidi record di dati: per ogni sessione viene creato un file di log separato in modo da poterli confrontare in un secondo momento.

Il logging può generare molti dati, specialmente quando si scrive un'applicazione complessa con Python. Gli sviluppatori utilizzano Python Logging to File (un file di log creato dal modulo Python logging che viene popolato con le informazioni di logging tramite un handler) per raccogliere questi dati. È importante che il file di log funzioni in modo asincrono, altrimenti il logging in Python potrebbe bloccare l'esecuzione dello script.

Analisi degli errori con Python logging: i 5 livelli di priorità dei log

Alcuni sviluppatori utilizzano la funzione print per verificare la presenza di errori nei loro script. A tale scopo inseriscono l’istruzione in tutti i punti che potrebbero rappresentare una fonte di errore. Altri usano print persino in modo preventivo all'interno dei loro script. Un problema di questo metodo è che poi dovranno ripassare l'intero codice per commentare o cancellare l’istruzione. In caso contrario, il testo in uscita può apparire quando gli utenti utilizzano il programma. Il codice sorgente appare, inoltre, molto disordinato.

Il semplice logging consente di risparmiare lavoro aggiuntivo e fornisce una soluzione più elegante per l'analisi degli errori. Il Python logging distingue cinque diversi livelli di gravità degli errori o “Level of Severity”. Potete ovviamente creare anche filtri di log personalizzati. Il modulo logging di Python integrato di Vinay Sajip offre già una suddivisione utile dei livelli di gravità:

Nome del livello di logging Utilizzo Possibile messaggio
Debug Diagnosi dei problemi, molto dettagliata Rientro inaspettato nella linea XY
Info Fornisce un feedback sul corretto funzionamento del sistema La funzione 1*1 viene eseguita
Warning L'applicazione funziona correttamente, ma si è verificata una situazione imprevista o è stato lanciato un avvertimento per un problema futuro Lo spazio di archiviazione è quasi esaurito
Error Non è stato possibile eseguire una funzione perché si è verificato un problema Si è verificato un errore e l'azione è stata annullata
Critical Si è verificato un problema grave. Potrebbe essere necessario abortire l'intera applicazione Errore grave: il programma non può accedere a questo servizio e deve essere abortito

Ciascuno dei diversi livelli rappresenta informazioni su eventi di crescente importanza. I livelli di Python logging sono funzioni statiche. Nella programmazione orientata agli oggetti queste funzioni costituiscono il contenuto di una classe. Per ogni istanza della classe all'interno di un oggetto le funzioni statiche sono sempre le stesse. Non cambiano e sono presenti anche se non viene chiamata nessuna istanza. Error, ad esempio, è un messaggio di errore in tutte le istanze. Se viene chiamata nello stesso oggetto di esecuzione, il messaggio di errore associato rimane lo stesso. Per altre azioni è possibile specificare un messaggio di errore diverso.

Debug è il livello più basso, motivo per cui anche la priorità delle informazioni emesse è ridotta. Questo non significa, tuttavia, che la gravità di un errore sia superiore a quella di Critical. Debug include tutti gli altri livelli e genera, quindi, tutti i messaggi fino al Critical Error.

Il modulo logging di Python

Il modulo logging di Python fa parte della libreria Python. L'interfaccia di logging non solo interagisce perfettamente con il resto del codice sorgente, ma è anche sempre pronta all'uso. Il semplice logging e l'invio delle informazioni a un file viene rapidamente integrata nel codice esistente tramite un handler. Il modulo logging di Python ha funzioni aggiuntive che possono essere utilizzate per personalizzare lo strumento. Questi sono i componenti principali del modulo logging:

  • Logger
  • Handler
  • Filter
  • Formatter

Le istanze vengono raccolte nell'istanza LogRecord e scambiano informazioni all'interno dell'istanza.

Logger

Gli ogetti logger registrano le azioni durante l'esecuzione di un programma. I logger non vengono istanziati direttamente, ma attraverso la funzione logging.getLogger(name). Assegnate un nome al logger per visualizzare, ad esempio, le gerarchie in modo strutturato. In Python separate i figli dai pacchetti con un punto. Il pacchetto log può quindi avere i pacchetti subordinati log.bam o log.bar.loco. Analogamente, i logger lavorano in modo che l'oggetto "log" riceva le informazioni dei suoi figli "log.bam" e "log.bar.loco".

Handler

Gli oggetti handler ricevono le informazioni dai logger e le inoltrano. Gli handler sono una classe di base che determina come agisce l'interfaccia delle istanze handler. Con la rispettiva classe handler si definisce la destinazione. StreamHandler invia le informazioni agli stream, mentre FileHandler le invia ai file. Potete utilizzare diversi handler per un programma che inviano messaggi dallo stesso logger. Questo è utile se, per esempio, volete visualizzare le informazioni di debug nella console e importanti messaggi di errore in un file separato.

Con il metodo setLevel() potete impostare il livello minimo di gravità di un messaggio di log per essere inoltrato a questo handler. Invece di logger.setLevel (che determina il livello di logging), il metodo è chiamato [handlername].setLevel (vedi la riga 5 del modello di codice: fh.setLevel).

Formatter

A differenza degli handler, i formatter (oggetti di formattazione) possono essere istanziatidirettamente nel codice dell'applicazione. Queste istanze vengono utilizzate per specificare il formato in cui il messaggio viene visualizzato nel file di log. Se non utilizzate alcuna formattazione, appare solo il messaggio del logger. Con la seguente funzione potete chiamare il formatter e definire il formato del messaggio e della data:

logging.Formatter.__init__(fmt=[formato messaggio], datefmt=[formato data])
#o anche:
logging.Formatter.__init__(fmt=None, datefmt=None)

Se non specificate un formato per la data nell'attributo, il formatter utilizza il formato americano: "Anno-Mese-Giorno Ore:Minuti:Secondi".

Filter

I filter consentono di definire i messaggi in uscita in modo ancora più preciso. I filter vengono impostati per primi e poi aggiunti al corrispondente handler o logger usando il metodo addFilter(). Se per via delle proprietà del messaggio il valore di un filter è false, questo non viene trasmesso. Utilizzate la funzione logging.Filter(name=fh), in cui l'attributo fh sta per qualsiasi nome di logger, per consentire i dati di log di un particolare logger e bloccare tutti gli altri.

Un esempio pratico del modulo di logging di Python

Python mette a disposizione degli sviluppatori il modulo Turtle per testare i comandi di base mediante un esempio. Nell'esempio che segue, l'utente utilizza Turtle. Questo strumento dovrebbe muoversi in avanti su uno sfondo verde, girare a sinistra, continuare a muoversi e poi disegnare un cerchio. Nell'esempio includiamo i comandi Python logging Info ed Error:

# -*- coding: UTF-8 -*-
import turtle
import logging
turtle.bgcolor("green")
turtle.fd(30)
turtle.lt(90)
turtle.fd(50)
logging.info('A te funziona.')
turtle.circle(50)
logging.error('Ups, qualcosa è andato storto.')

Nell'immagine sopra potete vedere come appare il risultato. Il modulo Turtle (finestra a sinistra) ha accettato le istruzioni e funziona come prescritto. Nella finestra a destra il codice include le istruzioni Turtle e le istruzioni di logging dei livelli INFO ed ERROR. La forma di output tipica di un messaggio di log è la seguente: [Gravità]:[Origine del messaggio]:[Contenuto del messaggio].

La console (Console 1/A) nell'esempio mostra, tuttavia, solo il messaggio di Python logging ERROR: Errore:root:Ups, qualcosa è andato storto.

Questo perché il modulo Python logging è impostato di default su WARNING. Il modulo omette tutte le informazioni più dettagliate fino a quando queste impostazioni non vengono modificate.

Modificare il livello di Python logging

Utilizzate il seguente comando per cambiare l'impostazione al livello DEBUG:

import logging
logging.basicConfig(level=logging.DEBUG)

Nell'immagine sopra la console visualizza il logging per ogni nuova chiamata. Se il programma viene abortito, la console cancella tutti i record. Per tenere traccia dei dati di logging è necessario utilizzare un file di log. Questa pratica viene chiamata Logging to File in inglese, ovvero logging su file.

Memorizzare il Python logging in un file

Il logging su file funziona in due modi. Potete creare un file di log mediante le impostazioni di base o utilizzare un handler. Se non indicate una destinazione, Python logging memorizza le informazioni temporaneamente nella console.

Utilizzate il seguente comando per creare un file per il vostro Python logging:

import logging
logging.basicConfig( level=logging.DEBUG, filename='example.log')

Il FileHandler è un'istanza della classe di logging, che agisce insieme all'istanza di logging. Essa definisce il luogo in cui vengono inviati i dati di logging e in quale forma. Il modulo di logging della libreria Python contiene altri logging handler oltre al FileHandler, come lo StreamHandler e il NullHandler. Si consiglia comunque di utilizzare un file di log per la successiva valutazione dei dati di logging.

Ecco come potete creare un FileHandler che memorizzi i messaggi di debug in un file:

Nell'immagine sopra la funzione logging.getLogger() chiama il modulo logging di Python. "fh" è definito come FileHandler con l'attributo "debug.log". Così fh crea il file di log "debug.log" e vi invia gli eventuali messaggi di log. Il metodo addHandler() assegna l’handler corrispondente al logger. Potete nominare liberamente il file di log.

Potete utilizzare le seguenti funzioni per fare una prova:

import logging
logger = logging.getLogger('Esempio_Log')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('debug.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
logger.debug('Messaggio di debug')
logger.info('Messaggio info')
logger.warning('Avviso')
logger.error('Messaggio di errore')
logger.critical('Errore grave')

Se il file di log che avete creato con Python logging su file deve fornire informazioni utili per task specifici, i messaggi semplici potrebbero non essere sufficienti. Un timestamp e il nome del logger aiutano a classificare meglio le note. La seguente schermata mostra un esempio di come potete specificare il formato utilizzando gli attributi di Formatter. Nella finestra di Notepad debug.log, l'output di testo specifica i messaggi di log con data, ora, nome del logger, livello del log e messaggio.

Ecco ancora una volta il codice per fare una prova:

import logging
logger = logging.getLogger('Esempio_Log')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('debug.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.debug('Messaggio di debug')
logger.info('Messaggio info')
logger.warning('Avviso')
logger.error('Messaggio di errore')
logger.critical('Errore grave')

In sintesi

Python logging è uno strumento pratico per la prevenzione degli errori, il controllo dopo gli attacchi hacker o semplicemente per l'analisi. Mentre altri linguaggi di programmazione utilizzano logging di terzi, il modulo di logging di Python fa parte della libreria standard. Se inserite il metodo nel vostro codice, vengono generati messaggi di log di diversi livelli, sia nei file che nella console. La formattazione, i filtri e gli handler garantiscono un'impostazione facile. Assicuratevi di scegliere nomi facilmente riconoscibili per i vostri logger e i loro figli per rendere più facile il lavoro con i file di log in Python.


Offerta Black Friday
Non perderti la nostra offerta speciale sui prodotti pensati per il tuo successo online. Approfittane subito, hai tempo solo fino al 30 novembre.
Sconti fino al 98%