Guida Completa ai Formati del Log in Python: Configurazioni, Custom Formatter ed Esempi Pratici
Il logging
è una componente cruciale nello sviluppo software, in particolare
quando si tratta di monitorare e diagnosticare problemi nelle applicazioni. In
Python
, il modulo logging
offre una struttura flessibile e potente per
gestire i log
. Nell'articolo Guida Completa al Logging in Python dalla Configurazione di
Base alla Configurazione Avanzata ti abbiamo mostrato come configurare i
logger
in modo automatico o manuale, sottolineando i pregi e i difetti di
ciascuna scelta. Nell'articolo Livelli di Log in Python: Tutto Quello che Devi Sapere per un
Logging Efficace abbiamo mostrato come gestire i livelli di log per
attribuire ad ogni messaggio un peso ed un ruolo.
Questo articolo affronta in dettaglio il tema dei formati di log
disponibili
in Python. L'articolo mostra come configurare i messaggi di log, come
personalizzarli, e offre moltissimi esempi di utilizzo.
Opzioni di formattazione
La formattazione dei messaggi gioca un ruolo fondamentale nella
personalizzazione dei file di log. A seconda del livello di granularità
che vogliamo raggiungere, possiamo inserire più o meno informazioni
all'interno del file di log
. Ovviamente, non esiste una regola precisa da
seguire, ma, a seconda della volontà del team di sviluppo, si può decidere che
tipo di informazioni inserire.
Le informazioni all'interno dei file di log sono veicolate per mezzo dei
placeholder. Un placeholder è una stringa così formata:
%(NOME_PLACEHOLDER)s
, dove NOME_PLACEHOLDER
rappresenta il nome
dell'informazione da stampare. Al posto della s
finale, si può avere la d
se il placeholder rappresenta un intero.
Il modulo logging
di Python fornisce una moltitudine di opzioni che
consentono la formattazione dei vari messaggi di log. Di seguito sono riportati
gli esempi più utilizzati di placeholder che è possibile inserire nei formati
dei log:
%(asctime)s
: ora del log%(name)s
: nome del logger%(levelname)s
: livello di log%(message)s
: messaggio di log%(filename)s
: nome del file da cui è stato emesso il log%(module)s
: nome del modulo da cui è stato emesso il log%(lineno)d
: numero di riga nel file da cui è stato emesso il log%(funcName)s
: nome della funzione da cui è stato emesso il log%(pathname)s
: percorso completo del file%(process)s
: ID del processo%(processName)s
: nome del processo%(thread)s
: ID del thread%(threadName)s
: nome del thread
Esempi di log
I precedenti placeholder possono essere usati per comporre i messaggi di log che saranno visibili nei file, sulla console, etc. Sono innumerevoli le opzioni possibili per formattare i log, di seguito vedremo alcuni esempi.
Formato semplice
Il formato semplice prevede la stampa del solo messaggio di log.
formatter = logging.Formatter('%(message)s')
logger.info("messaggio")
L'output del formato è:
messaggio
Formato con Data e Ora
Aggiungiamo al formato semplice la stampa della Data e dell'ora.
formatter = logging.Formatter('%(asctime)s - %(message)s')
logger.info("messaggio con data e ora")
L'output del formato è:
2024-01-01 12:00:00,000 - messaggio con data e ora
Formato con livello di log
Possiamo aggiungere al formato con data e ora, il livello di log.
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
logger.info("messaggio con data e ora e livello di log")
L'output del formato è:
2024-01-01 12:00:00,000 - INFO - messaggio con data e ora e livello di log
Formato completo
Come visto le combinazioni dei messaggi di log posso essere tantissime. Nella prossima stampa inseriamo tutte le opzioni elencate così da vedere che output producono.
formatter = logging.Formatter('''
ASCTIME:%(asctime)s
NAME:%(name)s
LEVELNAME:%(levelname)s
MESSAGE:%(message)s
FILENAME:%(filename)s
MODULE:%(module)s
LINENO:%(lineno)d
FUNCNAME%(funcName)s
PATHNAME:%(pathname)s
PROCESS:%(process)s
PROCESSNAME:%(processName)s
THREAD:%(thread)s
THREADNAME:%(threadName)s
'''
)
logger.info("Messaggio completo")
L'output del formato è:
ASCTIME:2024-07-01 20:00:47,803
NAME:root
LEVELNAME:INFO
MESSAGE:Messaggio completo
FILENAME:opzioni_formattazione.py
MODULE:opzioni_formattazione
LINENO:43
FUNCNAME<module>
PATHNAME:/home/xm3ron/src/test_log_python/opzioni_formattazione.py
PROCESS:104881
PROCESSNAME:MainProcess
THREAD:128862875727680
THREADNAME:MainThread
Formatter
personalizzati
Oltre ai formati predefiniti, è possibile creare formatter
personalizzati
estendendo la classe logging.Formatter
. Questo permette di aggiungere logica
personalizzata nella formattazione dei messaggi.
import logging
class CustomFormatter(logging.Formatter):
def format(self, record):
record.custom_attribute = 'Valore custom formatter'
return super().format(record)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
formatter = CustomFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(custom_attribute)s')
console_handler.setFormatter(formatter)
logger.info('Messaggio con formatter personalizzato.')
Aggiunta di Attributi Personalizzabili
Puoi aggiungere attributi personalizzati al tuo log, come l'id dell'utente e la versione dell'app. Nell'esempio seguente sono inseriti proprio questi attributi.
import logging
class CustomFormatter(logging.Formatter):
def format(self, record):
record.user_id = '89'
record.app_version = '1.2.0'
return super().format(record)
logger = logging.getLogger('custom_logger')
logger.setLevel(logging.DEBUG)
# Crea un handler per la console
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
formatter = CustomFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s - User ID: %(user_id)s - App Version: %(app_version)s')
console_handler.setFormatter(formatter)
logger.info('Messaggio con attributi personalizzati.')
Formattazione condizionale
Puoi applicare diverse formattazioni al tuo log, a seconda del livello di log del messaggio, come segue.
import logging
class ConditionalFormatter(logging.Formatter):
def format(self, record):
if record.levelno == logging.ERROR:
self._style._fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s - ERROR OCCURRED'
else:
self._style._fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
return super().format(record)
logger = logging.getLogger('conditional_logger')
logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
logger.addHandler(console_handler)
formatter = ConditionalFormatter()
console_handler.setFormatter(formatter)
logger.info('Messaggio informativo.')
logger.error('Messaggio di errore.')
Conclusioni
Il modulo logging
di Python offre una vasta gamma di opzioni per configurare
e personalizzare i messaggi di log
. Dalla semplice configurazione di base a
configurazioni avanzate con formatter
personalizzati e file di
configurazione, è possibile adattare il sistema di logging
alle esigenze
specifiche del progetto. Sperimenta con i vari placeholder e approcci per
trovare la configurazione ottimale per il tuo contesto.
Spero che questo articolo ti abbia fornito una comprensione approfondita dei
formati del log
in Python e delle possibilità offerte dalla libreria
logging
. Buon lavoro con il logging
!