logging - Segnala messaggi di stato, di errore e informativi
Scopo: Segnala messaggi di stato, di errore e informativi
Il modulo logging definisce una API standard per segnalare errori e informazioni di stato da applicazioni e librerie. Il vantaggio chiave dell'avere una API di segnalazione fornita da un modulo di libreria standard è che tutti i moduli Python possono concorrere alla segnalazione, in modo che il registro di un'applicazione possa includere messaggi da moduli di terze parti.
Componenti di logging
Il sistema di registrazione è composto da quattro tipi di oggetti. Ogni modulo o applicazione che voglia registrare usa una istanza di Logger
per aggiungere informazioni ai registri. La chiamata del logger crea un LogRecord
, che viene usato per mantenere le informazioni in memoria fino a quando sono elaborate. Un Logger
potrebbe avere un numero di oggetti Handler
(gestori - n.d.t.) configurati la ricezione ed elaborazione dei record di registrazione. Handler
usa l'oggetto Formatter
per trasformare i record di registrazione in messaggi in uscita.
Registrazioni nelle Applicazioni contro Registrazioni nelle Librerie
Gli sviluppatori di applicazioni e gli autori di librerie possono entrambi utilizzare logging, ma ognuna di queste categorie ha diverse considerazioni da tenere a mente.
Gli sviluppatori dell'applicazione configurano il modulo logging, smistando i messaggi agli appropriati canali in uscita. E' possibile registrare messaggi con livelli di verbosità diversi oppure verso destinazioni diverse. Sono inclusi gestori per la scrittura dei messaggi di su file, verso indirizzi HTTP GET/POST, email tramite SMTP, socket generici oppure verso meccanismi di registrazione specifici di un sistema operativo ed è possibile creare classi di destinazione delle registrazioni personalizzate per particolari esigenze che non sono coperte dalle classi built-in.
Gli sviluppatori di librerie possono usare logging e avere anche meno lavoro da fare. Semplicemente possono creare una istanza di logger per ciascun contesto, usando un nome appropriato, quindi registrare i messaggi usando i livelli standard. Fintanto che una libreria usa l'API di registrazione con livelli e nomenclature consistenti, l'applicazione può essere configurata per mostrare o nascondere i messaggi dalla libreria, come si desidera.
Registrazione verso un File
La maggior parte delle applicazioni sono configurate per registrare verso un file. Si usi la funzione basicConfig()
per impostare il gestore predefinito in modo che i messaggi di debug siano scritti a un file.
# logging_file_example.py
import logging
LOG_FILENAME = 'logging_example.out'
logging.basicConfig(
filename=LOG_FILENAME,
level=logging.DEBUG,
)
logging.debug('Questo messaggio dovrebbe andare nel file di log')
with open(LOG_FILENAME, 'rt') as f:
body = f.read()
print('FILE:')
print(body)
Terminata l'esecuzione dello script il messaggio di log viene scritto in logging_example.out
:
$ python3 logging_file_example.py FILE: DEBUG:root:Questo messaggio dovrebbe andare nel file di log DEBUG:root:Questo messaggio dovrebbe andare nel file di log DEBUG:root:Questo messaggio dovrebbe andare nel file di log DEBUG:root:Questo messaggio dovrebbe andare nel file di log DEBUG:root:Questo messaggio dovrebbe andare nel file di log DEBUG:root:Questo messaggio dovrebbe andare nel file di log
Rotazione dei File di Registrazione
Se si esegue lo script ripetutamente, i messaggi di log aggiuntivi sono accodati al file. Per creare ogni volta che il programma viene eseguito un nuovo file, si passi un argomento filemode
a basicConfig()
con il valore 'w'
. Piuttosto che gestire la creazione di file in questo modo, tuttavia, è meglio usare un RotatingFileHandler
, che crea automaticamente nuovi file e preserva allo stesso tempo i vecchi file di registrazione.
# logging_rotatingfile_example.py
import glob
import logging
import logging.handlers
LOG_FILENAME = 'logging_rotatingfile_example.out'
# Impostazione di un logger specifico con il livello di output desiderato
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)
# Aggiunta dell'handler dei messaggi di registrazione al logger
handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME,
maxBytes=20,
backupCount=5,
)
my_logger.addHandler(handler)
# Registrazione di qualche messaggio
for i in range(20):
my_logger.debug('i = %d' % i)
# Visualizzazione dei file che sono stati creati
logfiles = glob.glob('%s*' % LOG_FILENAME)
for filename in sorted(logfiles):
print(filename)
Il risultato è sei file distinti, ognuno con una parte della storia delle registrazioni per l'applicazione:
$ python3 logging_rotatingfile_example.py logging_rotatingfile_example.out logging_rotatingfile_example.out.1 logging_rotatingfile_example.out.2 logging_rotatingfile_example.out.3 logging_rotatingfile_example.out.4 logging_rotatingfile_example.out.5
Il file con le registrazioni più recenti è sempre logging_rotatingfile_example.out
, e ogni volta che esso raggiunge il limite di dimensione viene rinominato con il suffisso .1.
. Ognuno dei file di backup esistenti viene rinominato incrementando il suffisso (.1.
) diventa .2.
ecc.) mentre il file .5.
viene eliminato.
maxBytes
a un valore appropriato in un programma reale.Livelli di Dettaglio
Un'altra utile caratteristica dell'API di logging è la capacità di produrre diversi messaggi per diversi livelli di registrazione. Questo significa che il codice può essere equipaggiato con messaggi di debug, ad esempio, e il livello di registrazione può essere impostato in modo che questi messaggi di debug non siano scritti in un sistema in produzione. La tabella seguente mostra i livelli di registrazione definiti nel modulo.
Livello | Valore |
---|---|
CRITICAL | 50 |
ERROR | 40 |
WARNING | 30 |
INFO | 20 |
DEBUG | 10 |
UNSET | 0 |
Il messaggio di registrazione viene emesso se il gestore e il logger sono configurati per l'emissione di messaggi di quel livello o superiore. Ad esempio, se un messaggio è CRITICAL
, e il logger è impostato a ERROR
, il messaggio viene emesso (50 > 40). Se un messaggio è un WARNING
, e il logger viene impostato per produrre solo ERROR
, il messaggio non viene emesso (30 < 40).
# logging_level_example.py
import logging
import sys
LEVELS = {
'debug': logging.DEBUG,
'info': logging.INFO,
'avvertimento': logging.WARNING,
'errore': logging.ERROR,
'critico': logging.CRITICAL,
}
if len(sys.argv) > 1:
level_name = sys.argv[1]
level = LEVELS.get(level_name, logging.NOTSET)
logging.basicConfig(level=level)
logging.debug('Questo è un messaggio di debug')
logging.info('Questo è un messaggio di informazione')
logging.warning('Questo è un messaggio di avvertimento')
logging.error('Questo è un messaggio di errore')
logging.critical('Questo è un messaggio critico')
Si esegua lo script con un parametro tipo 'debug' oppure 'avvertimento' per vedere quali messaggi vengono mostrati ai livelli diversi.
$ python3 logging_level_example.py debug DEBUG:root:Questo è un messaggio di debug INFO:root:Questo è un messaggio di informazione WARNING:root:Questo è un messaggio di avvertimento ERROR:root:Questo è un messaggio di errore CRITICAL:root:Questo è un messaggio critico
$ python3 logging_level_example.py info INFO:root:Questo è un messaggio di informazione WARNING:root:Questo è un messaggio di avvertimento ERROR:root:Questo è un messaggio di errore CRITICAL:root:Questo è un messaggio critico
Nominare le Istanze di Logging
Tutti i precedenti messaggi di registrazione hanno '
# logging_modules_example.py
import logging
logging.basicConfig(level=logging.WARNING)
logger1 = logging.getLogger('package1.module1')
logger2 = logging.getLogger('package2.module2')
logger1.warning('Questo messaggio viene da un modulo')
logger2.warning('Questo viene da un altro modulo')
Il risultato mostra i diversi nomi di modulo per ciascuna riga in uscita.
$ python3 logging_modules_example.py WARNING:package1.module1:Questo messaggio viene da un modulo WARNING:package2.module2:Questo viene da un altro modulo
L'alberatura del Logging
Le istanze di Logger
sono configurate come una struttura ad albero, in base ai loro nomi, come illustrato nella figura seguente. Tipicamente, ogni applicazione o libreria definisce un nome base, impostando come figli i logger dei moduli individuali. Il logger radice non ha nome.
.
La struttura ad albero è utile per configurare le registrazioni in quanto implica che ciascun logger non deve avere bisogno del proprio insieme di gestori. Nel caso in cui un logger non abbia gestori, l'elaborazione del messaggio viene eseguita dal suo genitore. Questo vuol dire che per molte applicazioni è necessario configurare solamente i gestori sul logger radice, e tutte le informazioni da registrare vengono raccolte e inviate allo stesso posto, come mostra la seguente figura.
.
La struttura ad albero consente anche l'impostazione di diversi livelli di verbosità, di gestori e di formattatori per diverse parti di una applicazione o libreria per controllare quali messaggi debbano essere registrati e quali ignorati, come da seguente figura.
.
Integrazione con il modulo Warnings
Il modulo logging si integra con il modulo warnings tramite captureWarnings()
, che configura warnings per inviare messaggi tramite il sistema di registrazione invece che esporli direttamente.
# logging_capture_warnings.py
import logging
import warnings
logging.basicConfig(
level=logging.INFO,
)
warnings.warn('Questo avvertimento non viene registrato')
logging.captureWarnings(True)
warnings.warn('Questo avvertimento viene registrato')
Il messaggio di avvertimento viene inviato a un logger chiamato py.warnings
usando il livello WARNING
.
$ python3 logging_capture_warnings.py logging_capture_warnings.py:10: UserWarning: Questo avvertimento non viene registrato warnings.warn('Questo avvertimento non viene registrato') WARNING:py.warnings:logging_capture_warnings.py:14: UserWarning: Questo avvertimento viene registrato warnings.warn('Questo avvertimento viene registrato')
Vedere anche:
- logging
- La documentazione della libreria standard per questo modulo è estensiva, e include tutorial e materiale di riferimento che va oltre gli esempi qui presentati.
- Note di portabilità da Python 2 a Python 3 per logging
- warnings
- Avvertimenti non fatali
- logging_tree
- Pacchetto di terze parti di Brandon Rhodes per mostrare l'albero di logging per una applicazione.
- Logging cookbook
- Parte della documentazione della libreria standard, con esempi di uso di logging per diversi compiti.