Sostieni AppuntiFacili con una piccola donazione su PayPal
Dona con PayPalIl logging è un modo per tracciare eventi e messaggi che si verificano durante l’esecuzione del programma.
A differenza del semplice print(), il logging offre un modo più professionale, scalabile e controllato per monitorare il comportamento del codice.
In particolare, con logging è possibile:
DEBUG, INFO, WARNING, ERROR e CRITICAL;print().INFO
Esempio pratico: Se un’applicazione desktop con interfaccia grafica dovesse andare in crash, grazie al logging potremmo salvare automaticamente su un file .log tutti gli eventi che hanno portato all’errore, facilitando la diagnosi del problema.

La libreria logging di Python prevede 5 livelli principali di gravità dei messaggi:
| Livello di Log | Funzione | Descrizione |
|---|---|---|
| DEBUG | logging.debug() | Fornisce informazioni dettagliate utili per il debug e lo sviluppo. |
| INFO | logging.info() | Fornisce informazioni generali su ciò che sta accadendo nel programma. |
| WARNING | logging.warning() | Indica che c’è qualcosa che merita attenzione, ma il programma può continuare a funzionare. |
| ERROR | logging.error() | Segnala un problema imprevisto che si è verificato durante l’esecuzione del programma. |
| CRITICAL | logging.critical() | Indica un errore grave che potrebbe compromettere o interrompere il funzionamento dell’applicazione. |
Ecco un esempio di utilizzo base del modulo logging:
import logging
# Configurazione base
logging.basicConfig(level=logging.DEBUG)
logging.debug("Messaggio di debug - utile per capire il flusso del programma")
logging.info("Messaggio informativo - il programma sta funzionando correttamente")
logging.warning("Attenzione - qualcosa potrebbe non andare come previsto")
logging.error("Errore - qualcosa è andato storto")
logging.critical("Errore critico - il programma potrebbe arrestarsi")
INFO
Di default, il livello di logging impostato è WARNING, quindi verranno mostrati solo i messaggi di livello WARNING, ERROR e CRITICAL.
Per vedere anche i messaggi DEBUG e INFO, occorre impostare level=logging.DEBUG.
È possibile scrivere i messaggi di log anche su un file, utile per tracciare gli eventi nel tempo:
import logging
logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("Programma avviato correttamente.")
logging.warning("Connessione lenta.")
logging.error("Impossibile aprire il file richiesto.")
Questo codice genererà un file chiamato app.log contenente i messaggi con data, ora, livello e testo.
Il parametro format permette di personalizzare il formato del messaggio.
| Variabile | Descrizione |
|---|---|
%(asctime)s | Data e ora del log |
%(levelname)s | Livello del messaggio |
%(message)s | Testo del messaggio |
%(filename)s | Nome del file Python che ha generato il log |
%(lineno)d | Numero di riga del file |
%(name)s | Nome del logger (utile con più logger personalizzati) |
Esempio:
logging.basicConfig(
format="%(asctime)s - [%(levelname)s] (%(filename)s:%(lineno)d) - %(message)s",
level=logging.DEBUG
)
In applicazioni più complesse, è buona pratica creare logger personalizzati, invece di usare la configurazione globale.
import logging
# Creazione di un logger
logger = logging.getLogger("app_logger")
logger.setLevel(logging.DEBUG)
# Creazione di un handler per la console
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Creazione di un handler per il file
file_handler = logging.FileHandler("dettagli.log")
file_handler.setLevel(logging.DEBUG)
# Formattazione
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# Aggiunta degli handler al logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# Esempio di log
logger.debug("Questo messaggio va solo nel file.")
logger.info("Questo messaggio appare su console e file.")
logger.error("Errore critico!")
INFO
Questa tecnica è molto utile per progetti complessi, dove diversi moduli del programma generano log separati ma centralizzati.
In un progetto medio-grande, specialmente con approccio Object-Oriented, il logging è fondamentale per:
print()Il problema è che senza un servizio centralizzato, ogni file rischia di creare logger non uniformi o duplicare handlers, generando log doppi e configurazioni incoerenti.
Un LogService risolve tutto questo: una singola configurazione una sola volta, e poi in ogni modulo chiedi semplicemente:
logger = LogService.get_logger(__name__)
Così hai:
File: LogService.py:
import logging
from pathlib import Path
from typing import Optional
# Configurazioni globali
log_level = "INFO"
log_filename = "app.log"
full_path = Path(__file__).parent / log_filename
class LogService:
_is_configured = False
@classmethod
def get_logger(cls, name: Optional[str] = None):
if not cls._is_configured:
cls._configure()
return logging.getLogger(name)
@classmethod
def _configure(cls):
root_logger = logging.getLogger()
root_logger.setLevel(logging.getLevelName(log_level.upper()))
formatter = logging.Formatter(
"%(asctime)s - [%(levelname)s] (%(filename)s:%(lineno)d) - %(message)s"
)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
# File handler
file_handler = logging.FileHandler(full_path, encoding="utf-8")
file_handler.setFormatter(formatter)
# Evitiamo di aggiungere handler doppi
if not root_logger.handlers:
root_logger.addHandler(console_handler)
root_logger.addHandler(file_handler)
cls._is_configured = True
Esempio d’uso, file mail.py:
from LogService import LogService
class MailService:
def __init__(self):
self.logger = LogService.get_logger(__name__)
def send_email(self, to: str, subject: str, body: str):
self.logger.info(f"Invio email a: {to}")
try:
# simulazione invio email
if not to:
raise ValueError("Indirizzo email mancante")
# Log aggiuntivi
self.logger.debug(f"Oggetto: {subject}")
self.logger.debug(f"Corpo: {body}")
# Simulazione invio riuscito
self.logger.info("Email inviata con successo.")
except Exception as e:
self.logger.error(f"Errore nell'invio della mail: {e}")
raise
Scrivi un programma che:
logging.basicConfig() per impostare il livello a DEBUG;DEBUG, INFO, WARNING, ERROR, CRITICAL);level.Crea uno script che:
operazioni.log;Punti extra:
Applicazione che:
esegui_operazione() che simula varie azioni (es. connessione, caricamento file, elaborazione dati);INFO, WARNING, ERROR).try-except, ad esempio:
except Exception as e;logging.error(str(e)).INFO
Usa random.choice() per simulare eventi casuali positivi o di errore e osservali nel file operazioni.log.
Crea un logger personalizzato chiamato server_logger che:
INFO e superiori alla console;DEBUG) a un file server_debug.log;asctime, levelname, filename e message.Punti extra:
Server che:
logger inizializzato nel costruttore;avvia(), elabora_richiesta() e arresta() che scrivono log con diversi livelli (INFO, DEBUG, ERROR).try-except per gestire errori simulati (es. ValueError, ConnectionError) e registra:
ERROR con la descrizione dell’eccezione;CRITICAL se l’errore è grave e il server deve essere arrestato.INFO
Puoi creare un’eccezione personalizzata, ad esempio ServerCrashError(Exception), e sollevarla (raise) quando vuoi simulare un errore critico.
Nel blocco except, logga l’evento con logger.critical("Arresto del server: errore critico!").
1) Qual è la funzione principale del modulo logging in Python?
2) Qual è il livello di logging predefinito in Python?
3) Cosa fa il parametro 'filename' in logging.basicConfig()?
4) Quale livello di log si usa per messaggi di debug?
5) Cosa succede se non imposti 'level=logging.DEBUG' nella configurazione?
6) A cosa serve un 'logger personalizzato'?
7) Cosa rappresenta '%(asctime)s' nel formato dei log?
8) Come si definisce un formato personalizzato per i log?
9) Quale dei seguenti livelli è più grave?
10) Qual è una buona pratica nell'uso del logging?