Logging
- #python
- #programmazione
- #logging
In questa lezione
- 1. Introduzione
- 2. Tipi di logging
- 3. Utilizzo base
- 4. Salvare i log su file
- 5. Formattazione dei messaggi di log
- 6. Creazione di logger personalizzati
- 7. Logging unico in OOP
- 8. Esercizi
- 8.1 Esercizio - Logging Base
- 8.2 Esercizio - Log su File
- 8.3 Esercizio - Logger Personalizzato
- 9. Quiz a risposta multipla
1. Introduzione
Il 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:
- Registrare messaggi di diverso livello di importanza, come
DEBUG,INFO,WARNING,ERROReCRITICAL; - Controllare dove vengono scritti i messaggi di log, ad esempio su console, file, socket, o anche su server remoti;
- Formattare i messaggi di log per includere informazioni come data, ora, nome del modulo, livello di gravità e molto altro;
- Gestire i log in modo centralizzato, combinando più logger e handler per tenere traccia del comportamento dell’intera applicazione;
- Filtrare i messaggi per registrare solo quelli che ti interessano, migliorando così le prestazioni e la leggibilità;
- Diagnosticare e debuggare il codice in maniera più professionale e scalabile rispetto all’uso di semplici
print().
Nota
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.

2. Tipi di logging
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. |
3. Utilizzo base
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")
Nota
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.
4. Salvare i log su file
È 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.
5. Formattazione dei messaggi di log
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
)
6. Creazione di logger personalizzati
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!")
Nota
Questa tecnica è molto utile per progetti complessi, dove diversi moduli del programma generano log separati ma centralizzati.
7. Logging unico in OOP
In un progetto medio-grande, specialmente con approccio Object-Oriented, il logging è fondamentale per:
- Tracciare l’esecuzione del codice
- Registrare errori e warning
- Analizzare lo stato dell’applicazione
- Fare debug senza usare
print() - Produrre log sia su console che su file
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:
- formattazione uniforme
- log su file e console
- nessuna duplicazione di handler
- configurazione eseguita una sola volta
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
8. Esercizi
8.1 Esercizio - Logging Base
Scrivi un programma che:
- utilizzi
logging.basicConfig()per impostare il livello aDEBUG; - generi messaggi per ogni livello (
DEBUG,INFO,WARNING,ERROR,CRITICAL); - osserva quali livelli vengono mostrati modificando il parametro
level.
8.2 Esercizio - Log su File
Crea uno script che:
- salvi i messaggi di log in un file chiamato
operazioni.log; - includa nel formato data, ora, livello e messaggio;
- registri eventi simulando il funzionamento di un’app (es. “Connessione stabilita”, “Errore di rete”, ecc.).
Punti extra:
- Crea una classe
Applicazioneche:- contenga un metodo
esegui_operazione()che simula varie azioni (es. connessione, caricamento file, elaborazione dati); - utilizzi il modulo logging per registrare ogni evento con il livello appropriato (
INFO,WARNING,ERROR).
- contenga un metodo
- Gestisci possibili eccezioni con un blocco
try-except, ad esempio:- se viene simulato un errore (es. file mancante o connessione persa), catturalo con
except Exception as e; - registra l’errore nel file di log con
logging.error(str(e)).
- se viene simulato un errore (es. file mancante o connessione persa), catturalo con
Nota
Usa random.choice() per simulare eventi casuali positivi o di errore e osservali nel file operazioni.log.
8.3 Esercizio - Logger Personalizzato
Crea un logger personalizzato chiamato server_logger che:
- invii i log
INFOe superiori alla console; - invii tutti i log (anche
DEBUG) a un fileserver_debug.log; - utilizzi un formato che includa
asctime,levelname,filenameemessage.
Punti extra:
- Crea una classe
Serverche:- definisca un attributo
loggerinizializzato nel costruttore; - contenga metodi come
avvia(),elabora_richiesta()earresta()che scrivono log con diversi livelli (INFO,DEBUG,ERROR).
- definisca un attributo
- All’interno dei metodi della classe, utilizza
try-exceptper gestire errori simulati (es.ValueError,ConnectionError) e registra:- un messaggio
ERRORcon la descrizione dell’eccezione; - un messaggio
CRITICALse l’errore è grave e il server deve essere arrestato.
- un messaggio
Nota
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!").
9. Quiz a risposta multipla
Mettiti alla prova
0/10 risposte
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?