Tutorial sul logging in Python con Loguru: configurazione zero
Impara Loguru, il framework di logging più semplice per Python. Padroneggia rotazione file, logging strutturato, gestione delle eccezioni e sink personalizzati senza configurazione.
Hai fatto debug con le istruzioni print() per tutta la tua vita da coder. Magari hai provato il modulo di logging di Python una o due volte, ma sei tornato ai print perché sono più semplici.
In realtà esiste qualcosa di meglio, ed è altrettanto facile da usare.
Le istruzioni print non si possono salvare su file né attivare/disattivare facilmente. Il logging integrato di Python può farlo, ma richiede di scrivere codice di setup più lungo del tuo programma.
Loguru adotta un approccio diverso: il logging dovrebbe essere facile quanto stampare, ma molto più utile. Ottieni colori nel terminale, timestamp automatici e la possibilità di salvare tutto su file senza scrivere neanche una riga di configurazione.
In questo tutorial vedrai esempi pratici che rendono il logging naturale invece che gravoso. Scoprirai funzionalità che probabilmente non conoscevi, usando pattern di codice che rendono davvero il debug più semplice.
Se sei alle prime armi con il debug in Python o vuoi rafforzare le basi,costruire solide fondamenta di Python ti aiuta a capire quando e perché il logging diventa necessario.
Prime mosse con Loguru: magia a configurazione zero
Con il modulo logging standard, dovresti impostare handler, formatter e configurare tutto prima di vedere un singolo messaggio di log.
Per un confronto più approfondito sugli approcci di logging integrati in Python, dai un'occhiata a questotutorial completo sul logging che copre i metodi tradizionali.
Con Loguru, importi e inizi a loggare:
from loguru import logger
# Instead of print("Processing user data...")
logger.info("Processing user data...")# Instead of print(f"Found {count} records")
logger.info("Found {} records", count)Offerto da
L'output appare nel terminale con colori, timestamp e livelli di log automaticamente. Nessun setup richiesto.
Poniamo che tu stia costruendo un semplice web scraper. Ecco come cambia il tuo debug:
import requests
from loguru import logger
defscrape_website(url):
logger.info("Starting scrape for {}", url)
response = requests.get(url)
logger.debug("Response status: {}", response.status_code)if response.status_code ==200:
logger.success("Successfully scraped {} characters",len(response.text))return response.text
else:
logger.error("Failed to scrape {}: status {}", url, response.status_code)returnNoneOfferto da
Nota i diversi livelli di log (info, debug, success, error) e la formattazione con parentesi graffe. Funziona tutto subito senza file di configurazione o codice di setup.
Logging su file e rotazione semplificati
Quando fai debug con l'output in console, perdi tutto nel momento in cui chiudi il terminale. Non puoi cercare cosa è successo un'ora fa e, se il tuo script va in crash durante la notte, non c'è traccia di cosa sia andato storto. Inoltre non puoi condividere facilmente l'output di debug con i colleghi quando chiedi aiuto.
Il logging su file risolve salvando tutto in modo permanente.
Il logging tradizionale ti fa scrivere codice di configurazione per impostare i file handler. Devi specificare percorsi, creare directory e gestire i permessi. Con Loguru, aggiungere il logging su file è letteralmente una riga:
from loguru import logger
# Add file logging alongside console output
logger.add("app.log")
logger.info("This appears in both console and file")
logger.error("So does this error message")Offerto da
Ora tutto viene salvato in app.log e continua a comparire nel terminale.
Ma i file di log crescono a dismisura nel tempo. Un'app web in esecuzione per giorni può produrre gigabyte di log che alla fine riempiono il disco. La rotazione dei file risolve creando automaticamente nuovi file di log quando si verificano certe condizioni. Il file vecchio viene rinominato con un timestamp e ne parte uno nuovo:
# When app.log reaches 10 MB, it becomes app_2024-07-15_14-30-25.log# and a new empty app.log starts
logger.add("app.log", rotation="10 MB")# Or start a new file every day at midnight
logger.add("app.log", rotation="00:00")Offerto da
I timestamp predefiniti funzionano, ma spesso sono in UTC o difficili da leggere. Loguru ti permette di personalizzare i formati di data e ora in base alle tue esigenze:
# Custom timestamp format that's easier to read
logger.add("app.log",format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
rotation="1 day")Offerto da
Per i sistemi in produzione serve più controllo sui file vecchi. Il logging in produzione richiede di seguire le best practice di Python per garantire che i log siano mantenibili e sicuri. Senza gestione, i file di log si accumulano e consumano spazio:
# Keep only the last 10 rotated files, compress the rest
logger.add("production.log",
rotation="50 MB",# New file every 50MB
retention=10,# Keep only 10 old files
compression="zip")# Compress rotated filesOfferto da
Vediamolo in uno scenario realistico. Stai costruendo una pipeline dati che elabora ogni notte più file CSV, pulendo e validando i dati dei clienti prima di caricarli nel database. Devi tracciare quali file sono stati elaborati correttamente e intercettare eventuali problemi di qualità dei dati:
import pandas as pd
from loguru import logger
# Production-ready file logging setup
logger.add("data_processing_{time:YYYY-MM-DD}.log",
rotation="00:00",# New file daily
retention="1 week",# Keep 1 week of logsformat="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}")defprocess_csv_files(file_list):
logger.info("Starting batch processing of {} files",len(file_list))for filename in file_list:try:
df = pd.read_csv(filename)
logger.info("Loaded {} with {} rows", filename,len(df))# Your processing logic here
processed_df = df.dropna()
logger.success("Processed {} - kept {} rows", filename,len(processed_df))except Exception as e:
logger.error("Failed to process {}: {}", filename,str(e))
logger.info("Batch processing complete")Offerto da
I tuoi log vengono salvati con timestamp leggibili, i file ruotano automaticamente e i log vecchi si ripuliscono da soli. Puoi rivedere cosa è successo giorni dopo o inviare i file di log ai colleghi durante il troubleshooting.
Logging strutturato per app moderne
Quando esegui un'app web, i log diventano rapidamente un miscuglio di informazioni. Azioni utente, query al database, chiamate API ed errori si mescolano in un muro di testo. Non puoi filtrare facilmente per utente specifico, tracciare singole richieste o analizzare automaticamente i log per i sistemi di monitoraggio.
Le applicazioni data-driven traggono particolare beneficio dal logging strutturato. Se lavori con pipeline dati o analytics, sviluppare competenze da data analyst ti aiuta a capire quali informazioni catturare nei log.
Il logging basato su stringhe tradizionale peggiora la situazione. Ogni messaggio di log è solo testo, quindi estrarre dati significativi richiede regex complesse o ricerche manuali.
Il logging strutturato cambia le cose trattando le voci di log come oggetti dati anziché solo testo. Ogni voce di log diventa un record strutturato con campi ricercabili, rendendo facile eseguire query e analisi in modo programmatico.
Logging strutturato JSON con serialize=True
Loguru rende semplice il logging strutturato con l'opzione serialize=True:
Il parametro serialize=True dice a Loguru di emettere JSON anziché testo semplice. Invece di frasi leggibili, il tuo file di log ora contiene dati strutturati:
{"text":"User login","record":{"time":"2024-07-15T14:30:25","level":{"name":"INFO"},"extra":{"user_id":123,"ip_address":"192.168.1.1"}}}Offerto da
Questo formato funziona alla perfezione con gli strumenti di analisi dei log che possono cercare e filtrare automaticamente i dati JSON.
Context binding
Ma le applicazioni web hanno bisogno di più del solo dato strutturato. Serve contesto che colleghi le voci correlate. Quando elabori una richiesta utente, vuoi che tutti i log correlati condividano informazioni comuni come user ID o session ID.
Il context binding risolve aggiungendo informazioni persistenti al logger con logger.bind():
from loguru import logger
defprocess_user_order(user_id, order_data):# Create a logger with attached context
order_logger = logger.bind(user_id=user_id, order_id=order_data['id'])
order_logger.info("Starting order processing")
order_logger.debug("Validating payment method", method=order_data['payment'])
order_logger.info("Order processing complete", total=order_data['total'])Offerto da
Ora ogni log da order_logger include automaticamente user_id e order_id, rendendo facile tracciare tutti i log relativi a un ordine specifico.
Più sink per output diversi
Le applicazioni moderne hanno anche bisogno di output di log diversi per scopi diversi. Magari vuoi log leggibili in console durante lo sviluppo, ma log JSON per il monitoraggio in produzione. In Loguru, ogni destinazione di output è chiamata “sink” — pensala come un posto dove fluiscono i messaggi di log.
Loguru ti permette di aggiungere più sink con formati e regole diverse:
from loguru import logger
import sys
# Remove the default console output
logger.remove()# Sink 1: Human-readable console for development
logger.add(sys.stdout,
level="DEBUG",format="<green>{time:HH:mm:ss}</green> | {level} | {message}")# Sink 2: JSON file for production monitoring
logger.add("app.log",
serialize=True,
level="INFO")# Sink 3: Error-only file for alerts
logger.add("errors.log",
level="ERROR")Offerto da
La chiamata logger.remove() rimuove l'output console predefinito di Loguru così puoi impostare il tuo. Ogni logger.add() crea un nuovo sink con le proprie regole su cosa loggare e come formattarlo.
Ora le stesse istruzioni di log producono output diversi:
logger.debug("Processing started")# Only appears in console
logger.info("User data loaded")# Appears in console and app.log
logger.error("Database connection failed")# Appears in all three placesOfferto da
Esempio completo di Loguru: sistema di registrazione utenti
Vediamolo in un esempio più semplice e realistico di utilizzo di Loguru — un sistema base di registrazione utente:
from loguru import logger
import sys
# Set up multiple outputs
logger.remove()
logger.add(sys.stdout, level="INFO",format="{time:HH:mm:ss} | {message}")
logger.add("user_registration.log", serialize=True, level="INFO")
logger.add("errors.log", level="ERROR")defregister_user(email, password):# Create logger with user context
user_logger = logger.bind(email=email)
user_logger.info("Starting user registration")# Validate emailif"@"notin email:
user_logger.error("Invalid email format")returnFalse# Check if user exists
user_logger.debug("Checking if user already exists")# Simulate password hashing
user_logger.debug("Hashing password")# Save to database
user_logger.info("Saving user to database")
user_logger.success("User registration completed")returnTrue# Usage
register_user("[email protected]","secure123")Offerto da
Questa configurazione ti dà un output console leggibile durante lo sviluppo, log JSON strutturati per il monitoraggio automatico e log separati degli errori per gli alert. Il metodo bind() garantisce che tutti i log per ogni registrazione includano l'indirizzo email, rendendo il debug molto più semplice.
Gestione delle eccezioni con Loguru
Quando il tuo codice va in crash, di solito ottieni uno stack trace di base che ti dice dove è avvenuto l'errore, ma non molto sul perché. Perdi i valori delle variabili al momento del crash, rendendo difficile capire cosa sia andato storto. Anche la gestione tradizionale delle eccezioni richiede di avvolgere tutto in blocchi try-catch e loggare manualmente ogni eccezione.
Questo diventa particolarmente doloroso quando fai debug di problemi in produzione. Gli utenti segnalano errori, ma non riesci a riprodurli perché non hai il contesto presente quando si è verificato l'errore.
Loguru risolve con la cattura automatica delle eccezioni e tracebacks avanzati che mostrano esattamente cosa stava succedendo nel tuo codice quando le cose sono andate storte.
Cattura automatica delle eccezioni con @logger.catch
Il decorator @logger.catch cattura automaticamente qualsiasi eccezione che si verifichi in una funzione e la logga con tutto il contesto. I decorator come @logger.catch sono unconcetto intermedio di Python che può trasformare il modo in cui gestisci gli errori in tutto il codice.
from loguru import logger
@logger.catchdefdivide_numbers(a, b):
result = a / b
return result
# This automatically logs the exception with full traceback
result = divide_numbers(10,0)Offerto da
Invece che il programma vada in crash con un messaggio di errore di base, Loguru cattura l'eccezione e la logga con informazioni dettagliate, mentre il programma continua a girare. Il decorator funziona su qualsiasi funzione — metodi di classe, funzioni async o funzioni normali.
Traceback avanzati con ispezione delle variabili
Ma Loguru va oltre con tracebacks avanzati che mostrano i valori delle variabili a ogni livello dello stack di chiamate. Questa funzionalità si chiama “diagnose” ed è come avere un debugger integrato nei tuoi log:
from loguru import logger
# Enable enhanced tracebacks
logger.add("debug.log", diagnose=True)@logger.catchdefprocess_user_data(users):for user in users:
age = user['age']if age >0:
years_to_retirement =65- age
print(f"User {user['name']} has {years_to_retirement} years to retirement")# When this crashes, you'll see the exact values of 'users', 'user', and 'age'
users_data =[{"name":"Alice","age":30},{"name":"Bob","age":"invalid"},# This will cause an error]
process_user_data(users_data)Offerto da
Con diagnose=True, quando la funzione va in crash cercando di sottrarre una stringa a un numero, Loguru ti mostra esattamente cosa c'era in ogni variabile:
TypeError: unsupported operand type(s) for -: 'int' and 'str'
Variables values:
users = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": "invalid"}]
user = {"name": "Bob", "age": "invalid"}
age = "invalid"Offerto da
Questo livello di dettaglio rende il debug molto più rapido perché puoi vedere esattamente quali dati hanno causato il problema.
Gestione delle eccezioni consapevole dell'ambiente
Tuttavia, i tracebacks avanzati possono esporre informazioni sensibili come password o API key nei log di produzione. Loguru ti permette di controllare questo comportamento per ambienti diversi:
from loguru import logger
import os
# Development: Full diagnostic informationif os.getenv("ENVIRONMENT")=="development":
logger.add("app.log", diagnose=True, level="DEBUG")else:# Production: Basic logging without variable inspection
logger.add("app.log", diagnose=False, level="INFO")@logger.catchdefauthenticate_user(username, password, api_key):# In development, you'll see all variable values if this crashes# In production, sensitive data stays hiddenifnot username ornot password:raise ValueError("Missing credentials")Offerto da
Valutazione lazy per le performance
Un'altra funzione potente è la valutazione lazy, che migliora le prestazioni quando si loggano operazioni costose. A volte vuoi loggare informazioni complesse, ma solo se si verifica davvero un errore:
from loguru import logger
@logger.catchdefprocess_large_dataset(data):try:# Some complex processing that might fail
result = complex_calculation(data)return result
except Exception as e:# This expensive operation only runs if there's an error
logger.error("Processing failed with data: {data}",
data=lambda: expensive_data_summary(data))raisedefexpensive_data_summary(data):# This function takes time to run, summarizing huge datasetsreturn{"row_count":len(data),"columns":list(data.keys()),"memory_usage": data.memory_usage()}Offerto da
La sintassi lambda: crea una funzione che viene chiamata solo quando Loguru scrive effettivamente il messaggio di log. Se non si verifica alcun errore, expensive_data_summary() non viene mai eseguita, risparmiando tempo di elaborazione.
Strategie diverse per tipi di errore diversi
Puoi anche usare strategie diverse di gestione delle eccezioni per tipologie di errori diverse:
from loguru import logger
# Configure multiple outputs for different error severities
logger.add("warnings.log", level="WARNING",filter=lambda record: record["level"].name =="WARNING")
logger.add("critical_errors.log", level="ERROR")@logger.catch(level="ERROR")defcritical_database_operation(query):# Database errors get logged as ERROR level
execute_database_query(query)@logger.catch(level="WARNING", reraise=False)defoptional_feature(user_id):# Non-critical features log as WARNING and continue execution
send_optional_notification(user_id)defprocess_user_request(user_id, query):# Critical operation - if this fails, the whole request fails
critical_database_operation(query)# Optional operation - if this fails, request continues
optional_feature(user_id)Offerto da
Il parametro reraise=False dice a Loguru di loggare l'eccezione ma non rilanciarla, consentendo al programma di continuare. È utile per funzionalità opzionali che non dovrebbero interrompere il flusso principale.
Esempio completo: elaborazione file con gestione errori
Vediamo un esempio completo con un sistema di elaborazione file che gestisce con grazia diversi tipi di errori:
from loguru import logger
import os
# Set up environment-aware loggingif os.getenv("DEBUG"):
logger.add("file_processor.log", diagnose=True, level="DEBUG")else:
logger.add("file_processor.log", diagnose=False, level="INFO")@logger.catch(reraise=False)defvalidate_file_format(filename):ifnot filename.endswith(('.csv','.json','.xml')):raise ValueError(f"Unsupported file format: {filename}")@logger.catchdefload_file_data(filename):
logger.info("Loading file: {}", filename)# Expensive operation only logged on errors
logger.debug("File stats: {stats}",
stats=lambda:{"size": os.path.getsize(filename),"modified": os.path.getmtime(filename)})withopen(filename,'r')as f:return f.read()defprocess_files(file_list):
results =[]for filename in file_list:# Validation errors are logged but don't stop processing
validate_file_format(filename)try:# Loading errors are logged and do stop processing this file
data = load_file_data(filename)
results.append(data)
logger.success("Successfully processed {}", filename)except Exception:
logger.error("Skipping file {} due to loading error", filename)continuereturn resultsOfferto da
Questa configurazione ti dà cattura automatica delle eccezioni, contesto di errore dettagliato quando serve e strategie diverse per tipi di errori diversi. I tuoi log diventano molto più utili per il debug, mentre il codice resta pulito e leggibile.
Configurazione e personalizzazione avanzate di Loguru
Con la crescita delle applicazioni, troverai scenari in cui i default di Loguru non bastano. Magari ti serve un livello di log speciale per metriche di business, vuoi filtrare dati sensibili dai log o devi inviare alert a Slack quando si verificano errori.
La buona notizia è che Loguru è pensato per essere personalizzato senza perdere la sua semplicità. Puoi estenderlo in modi che nei sistemi di logging tradizionali richiederebbero configurazioni complesse, mantenendo il codice pulito e leggibile.
Vediamo le personalizzazioni più utili che risolvono problemi reali che affronterai in applicazioni di produzione.
Livelli e colori personalizzati
Loguru include livelli standard come INFO, DEBUG ed ERROR. Ma a volte ti serve qualcosa di specifico per la tua applicazione. Magari vuoi un livello speciale per metriche di performance o eventi di business.
Creare livelli personalizzati è semplice:
from loguru import logger
# Add a custom level for business metrics
logger.level("METRIC", no=38, color="<yellow>", icon="📊")# Add a custom level for security events
logger.level("SECURITY", no=45, color="<red><bold>", icon="🔒")# Now you can use these levels
logger.log("METRIC","Order completed in {} seconds",2.5)
logger.log("SECURITY","Failed login attempt from IP: {}","192.168.1.100")Offerto da
Il parametro no imposta la priorità del livello (numeri più alti = priorità più alta). I livelli standard usano: DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50.
Vediamolo in uno scenario di training di machine learning:
from loguru import logger
# Set up custom levels for ML tracking
logger.level("EPOCH", no=35, color="<cyan><bold>")
logger.level("CHECKPOINT", no=38, color="<green><bold>")# Configure output
logger.remove()
logger.add("training_{time:YYYY-MM-DD}.log", level="INFO")deftrain_model(model, data_loader, epochs=10):
logger.info("Starting training with {} epochs", epochs)for epoch inrange(epochs):# Log epoch progress with custom level
logger.log("EPOCH","Epoch {}/{} started", epoch +1, epochs)# Training logic here
loss =0.523-(epoch *0.05)# Simulated improving loss
accuracy =0.72+(epoch *0.03)# Simulated improving accuracy
logger.info("Loss: {:.4f}, Accuracy: {:.2%}", loss, accuracy)# Save checkpoint every 5 epochsif(epoch +1)%5==0:
logger.log("CHECKPOINT","Model saved at epoch {}", epoch +1)
logger.success("Training completed!")Offerto da
Intercettare e modificare i messaggi di log
A volte devi modificare i messaggi di log prima che vengano scritti. Casi comuni includono rimuovere dati sensibili, aggiungere ID di richiesta o riformattare i messaggi per strumenti specifici.
Loguru ti permette di intercettare i messaggi usando il parametro filter:
from loguru import logger
import re
defhide_sensitive_data(record):# Hide credit card numbers
record["message"]= re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b','XXXX-XXXX-XXXX-XXXX',
record["message"])# Hide email addresses
record["message"]= re.sub(r'\b[\w.-]+@[\w.-]+\.\w+\b','***@***.***',
record["message"])# Continue processing the logreturnTrue# Add the filter to your logger
logger.add("secure.log",filter=hide_sensitive_data)# Test it
logger.info("User paid with card 4532-1234-5678-9012")
logger.info("Contact email: [email protected]")Offerto da
Puoi anche usare i filtri per aggiungere informazioni contestuali:
from loguru import logger
import threading
defadd_thread_info(record):# Add thread name to every log message
record["extra"]["thread_name"]= threading.current_thread().name
returnTruedefadd_environment_info(record):# Add environment to production logs
record["extra"]["env"]="production"
record["extra"]["region"]="us-west-2"returnTrue# Apply multiple filters
logger.add("app.log",filter=lambda record: add_thread_info(record)and add_environment_info(record),format="{time} | {extra[env]} | {extra[thread_name]} | {message}")Offerto da
Sink personalizzati per servizi esterni
Un sink è dove confluiscono i tuoi log. Sebbene file e console siano comuni, spesso serve inviare i log a servizi esterni come Slack, email o sistemi di monitoraggio.
Ecco come creare un sink personalizzato che invia gli errori a Slack:
from loguru import logger
import requests
defsend_to_slack(message):"""Custom sink that sends messages to Slack"""# Parse the log record
record = message.record
# Only send errors and aboveif record["level"].no <40:# ERROR level is 40return# Format message for Slack
slack_message ={"text":f"🚨 {record['level'].name}: {record['message']}","attachments":[{"color":"danger","fields":[{"title":"Time","value":str(record["time"]),"short":True},{"title":"Function","value": record["function"],"short":True},{"title":"File","value":f"{record['file'].name}:{record['line']}","short":False}]}]}# Send to Slack webhook
webhook_url ="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
requests.post(webhook_url, json=slack_message)# Add the custom sink
logger.add(send_to_slack, level="ERROR")# Test it
logger.error("Database connection lost!")Offerto da
Ecco un altro esempio pratico — un sink personalizzato che raccoglie metriche di performance durante l'esecuzione dell'applicazione e le salva per l'analisi:
from loguru import logger
from collections import defaultdict
import json
classMetricsCollector:def__init__(self):
self.metrics = defaultdict(list)def__call__(self, message):"""This method is called for every log message"""
record = message.record
# Only process METRIC level logsif record["level"].name !="METRIC":return# Extract metric data from the 'extra' fields
extra = record["extra"]if"metric_name"in extra and"value"in extra:
self.metrics[extra["metric_name"]].append({"value": extra["value"],"timestamp": record["time"].timestamp()})defsave_metrics(self):"""Save all collected metrics to a JSON file"""withopen("metrics.json","w")as f:
json.dump(dict(self.metrics), f, indent=2)# Create the collector and add it as a sink
collector = MetricsCollector()
logger.add(collector)# Create the METRIC level
logger.level("METRIC", no=38)# Now when you log metrics, they're automatically collected# The bind() method attaches extra data to the log entry
logger.bind(metric_name="response_time", value=0.234).log("METRIC","API response")
logger.bind(metric_name="response_time", value=0.189).log("METRIC","API response")
logger.bind(metric_name="active_users", value=1523).log("METRIC","User count")# Later, save all metrics to file
collector.save_metrics()# The metrics.json file will contain:# {# "response_time": [# {"value": 0.234, "timestamp": 1627...},# {"value": 0.189, "timestamp": 1627...}# ],# "active_users": [# {"value": 1523, "timestamp": 1627...}# ]# }Offerto da
La bellezza di questo approccio è che il codice dell'app resta pulito — logghi semplicemente le metriche normalmente e il sink collector gestisce automaticamente l'archiviazione. Puoi sostituirlo facilmente con un sink che invia metriche a Prometheus, DataDog o qualsiasi altro servizio di monitoraggio.
Queste personalizzazioni ti danno la flessibilità di adattare Loguru alle tue esigenze specifiche mantenendo la semplicità che lo rende ottimo. Che tu stia costruendo uno script piccolo o una grande applicazione, puoi estendere Loguru per gestire le tue esigenze di logging senza file di configurazione complessi o boilerplate.
Conclusione
Loguru rende il logging in Python semplice come dovrebbe essere. Niente più file di configurazione, niente più setup di handler, niente più boilerplate. Importi e inizi a loggare con colori, timestamp e rotazione automatica dei file.
Hai visto come affronta i punti dolenti comuni: salvataggio dei log su file, rotazione automatica, cattura delle eccezioni con pieno contesto e invio dei log a servizi esterni. Le funzionalità di logging strutturato lo rendono pronto per la produzione, mentre livelli e sink personalizzati ti permettono di adattarlo a qualsiasi caso d'uso.
Usa Loguru quando:
Sei stanco del debug con print
Ti serve logging rapido in script o notebook
Stai costruendo app web che necessitano di log strutturati
Vuoi un tracciamento migliore delle eccezioni senza setup complesso
Inizia in piccolo. Sostituisci un'istruzione print con logger.info(). Non tornerai indietro.
FAQ su Loguru
In che modo Loguru si confronta con altre librerie di logging per Python?⌄
Loguru si distingue perché non richiede alcuna configurazione: puoi iniziare a loggare subito con from loguru import logger. A differenza del modulo di logging integrato di Python, che necessita di handler, formatter e setup complesso, Loguru offre colori, timestamp e rotazione dei file out of the box. Include anche tracebacks avanzati con ispezione delle variabili che altre librerie non forniscono.
Quali sono i principali vantaggi di usare Loguru rispetto al modulo di logging integrato di Python?⌄
Loguru elimina la complessità della configurazione, fornisce rotazione e retention automatiche dei file, offre logging JSON strutturato con serialize=True, include tracebacks avanzati delle eccezioni con valori delle variabili e supporta sink personalizzati per servizi esterni. Ottieni funzionalità di logging pronte per la produzione senza scrivere codice di setup.
Loguru gestisce in modo efficiente le applicazioni multithread?⌄
Sì, Loguru è thread-safe per impostazione predefinita e gestisce bene le applicazioni multithread. Puoi aggiungere informazioni sul thread ai log usando i filtri e il metodo logger.bind() funziona tra thread per mantenere il contesto. Le prestazioni di Loguru sono ottimizzate per il logging concorrente senza bloccare i thread.
Come funzionano la rotazione e la retention automatiche dei log in Loguru?⌄
Loguru offre una rotazione flessibile basata su dimensione del file (rotation="10 MB"), intervalli di tempo (rotation="00:00" per giornaliera) o condizioni personalizzate. La retention elimina automaticamente i file vecchi (retention=10 mantiene 10 file) e la compressione fa risparmiare spazio (compression="zip"). Tutto avviene automaticamente senza gestione manuale dei file.
Quali sono esempi pratici dell'uso dei sink personalizzati di Loguru?⌄
I sink personalizzati ti permettono di inviare i log a servizi esterni come Slack per gli alert sugli errori, raccogliere metriche per i sistemi di monitoraggio o formattare i log per strumenti specifici. Puoi creare sink che filtrano per livello di log, aggiungono informazioni contestuali o si integrano con servizi come DataDog, Prometheus o notifiche email per errori critici.
Sono un creator di contenuti sulla data science con oltre 2 anni di esperienza e uno dei più seguiti su Medium. Mi piace scrivere articoli dettagliati su AI e ML con un pizzico di sarcasmo, perché bisogna pur fare qualcosa per renderli un po’ meno noiosi. Ho pubblicato oltre 130 articoli e un corso su DataCamp, con un altro in arrivo. I miei contenuti sono stati visti da oltre 5 milioni di persone, 20.000 delle quali sono diventate follower sia su Medium che su LinkedIn.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Impara Python per lo sviluppo software, dalla scrittura di funzioni alla definizione di classi. Acquisisci le competenze necessarie per dare il via alla tua carriera da sviluppatore!
Hai fatto debug con le istruzioni
print()per tutta la tua vita da coder. Magari hai provato il modulo di logging di Python una o due volte, ma sei tornato ai print perché sono più semplici.In realtà esiste qualcosa di meglio, ed è altrettanto facile da usare.
Le istruzioni print non si possono salvare su file né attivare/disattivare facilmente. Il logging integrato di Python può farlo, ma richiede di scrivere codice di setup più lungo del tuo programma.
Loguru adotta un approccio diverso: il logging dovrebbe essere facile quanto stampare, ma molto più utile. Ottieni colori nel terminale, timestamp automatici e la possibilità di salvare tutto su file senza scrivere neanche una riga di configurazione.
In questo tutorial vedrai esempi pratici che rendono il logging naturale invece che gravoso. Scoprirai funzionalità che probabilmente non conoscevi, usando pattern di codice che rendono davvero il debug più semplice.
Se sei alle prime armi con il debug in Python o vuoi rafforzare le basi, costruire solide fondamenta di Python ti aiuta a capire quando e perché il logging diventa necessario.
Prime mosse con Loguru: magia a configurazione zero
Installare Loguru richiede un solo comando:
Con il modulo
loggingstandard, dovresti impostare handler, formatter e configurare tutto prima di vedere un singolo messaggio di log.Per un confronto più approfondito sugli approcci di logging integrati in Python, dai un'occhiata a questo tutorial completo sul logging che copre i metodi tradizionali.
Con Loguru, importi e inizi a loggare:
L'output appare nel terminale con colori, timestamp e livelli di log automaticamente. Nessun setup richiesto.
Poniamo che tu stia costruendo un semplice web scraper. Ecco come cambia il tuo debug:
Nota i diversi livelli di log (
info,debug,success,error) e la formattazione con parentesi graffe. Funziona tutto subito senza file di configurazione o codice di setup.Logging su file e rotazione semplificati
Quando fai debug con l'output in console, perdi tutto nel momento in cui chiudi il terminale. Non puoi cercare cosa è successo un'ora fa e, se il tuo script va in crash durante la notte, non c'è traccia di cosa sia andato storto. Inoltre non puoi condividere facilmente l'output di debug con i colleghi quando chiedi aiuto.
Il logging su file risolve salvando tutto in modo permanente.
Il logging tradizionale ti fa scrivere codice di configurazione per impostare i file handler. Devi specificare percorsi, creare directory e gestire i permessi. Con Loguru, aggiungere il logging su file è letteralmente una riga:
Ora tutto viene salvato in
app.loge continua a comparire nel terminale.Ma i file di log crescono a dismisura nel tempo. Un'app web in esecuzione per giorni può produrre gigabyte di log che alla fine riempiono il disco. La rotazione dei file risolve creando automaticamente nuovi file di log quando si verificano certe condizioni. Il file vecchio viene rinominato con un timestamp e ne parte uno nuovo:
I timestamp predefiniti funzionano, ma spesso sono in UTC o difficili da leggere. Loguru ti permette di personalizzare i formati di data e ora in base alle tue esigenze:
Per i sistemi in produzione serve più controllo sui file vecchi. Il logging in produzione richiede di seguire le best practice di Python per garantire che i log siano mantenibili e sicuri. Senza gestione, i file di log si accumulano e consumano spazio:
Vediamolo in uno scenario realistico. Stai costruendo una pipeline dati che elabora ogni notte più file CSV, pulendo e validando i dati dei clienti prima di caricarli nel database. Devi tracciare quali file sono stati elaborati correttamente e intercettare eventuali problemi di qualità dei dati:
I tuoi log vengono salvati con timestamp leggibili, i file ruotano automaticamente e i log vecchi si ripuliscono da soli. Puoi rivedere cosa è successo giorni dopo o inviare i file di log ai colleghi durante il troubleshooting.
Logging strutturato per app moderne
Quando esegui un'app web, i log diventano rapidamente un miscuglio di informazioni. Azioni utente, query al database, chiamate API ed errori si mescolano in un muro di testo. Non puoi filtrare facilmente per utente specifico, tracciare singole richieste o analizzare automaticamente i log per i sistemi di monitoraggio.
Le applicazioni data-driven traggono particolare beneficio dal logging strutturato. Se lavori con pipeline dati o analytics, sviluppare competenze da data analyst ti aiuta a capire quali informazioni catturare nei log.
Il logging basato su stringhe tradizionale peggiora la situazione. Ogni messaggio di log è solo testo, quindi estrarre dati significativi richiede regex complesse o ricerche manuali.
Il logging strutturato cambia le cose trattando le voci di log come oggetti dati anziché solo testo. Ogni voce di log diventa un record strutturato con campi ricercabili, rendendo facile eseguire query e analisi in modo programmatico.
Logging strutturato JSON con serialize=True
Loguru rende semplice il logging strutturato con l'opzione
serialize=True:Il parametro
serialize=Truedice a Loguru di emettere JSON anziché testo semplice. Invece di frasi leggibili, il tuo file di log ora contiene dati strutturati:Questo formato funziona alla perfezione con gli strumenti di analisi dei log che possono cercare e filtrare automaticamente i dati JSON.
Context binding
Ma le applicazioni web hanno bisogno di più del solo dato strutturato. Serve contesto che colleghi le voci correlate. Quando elabori una richiesta utente, vuoi che tutti i log correlati condividano informazioni comuni come user ID o session ID.
Il context binding risolve aggiungendo informazioni persistenti al logger con
logger.bind():Ora ogni log da
order_loggerinclude automaticamenteuser_ideorder_id, rendendo facile tracciare tutti i log relativi a un ordine specifico.Più sink per output diversi
Le applicazioni moderne hanno anche bisogno di output di log diversi per scopi diversi. Magari vuoi log leggibili in console durante lo sviluppo, ma log JSON per il monitoraggio in produzione. In Loguru, ogni destinazione di output è chiamata “sink” — pensala come un posto dove fluiscono i messaggi di log.
Loguru ti permette di aggiungere più sink con formati e regole diverse:
La chiamata
logger.remove()rimuove l'output console predefinito di Loguru così puoi impostare il tuo. Ognilogger.add()crea un nuovo sink con le proprie regole su cosa loggare e come formattarlo.Ora le stesse istruzioni di log producono output diversi:
Esempio completo di Loguru: sistema di registrazione utenti
Vediamolo in un esempio più semplice e realistico di utilizzo di Loguru — un sistema base di registrazione utente:
Questa configurazione ti dà un output console leggibile durante lo sviluppo, log JSON strutturati per il monitoraggio automatico e log separati degli errori per gli alert. Il metodo
bind()garantisce che tutti i log per ogni registrazione includano l'indirizzo email, rendendo il debug molto più semplice.Gestione delle eccezioni con Loguru
Quando il tuo codice va in crash, di solito ottieni uno stack trace di base che ti dice dove è avvenuto l'errore, ma non molto sul perché. Perdi i valori delle variabili al momento del crash, rendendo difficile capire cosa sia andato storto. Anche la gestione tradizionale delle eccezioni richiede di avvolgere tutto in blocchi try-catch e loggare manualmente ogni eccezione.
Questo diventa particolarmente doloroso quando fai debug di problemi in produzione. Gli utenti segnalano errori, ma non riesci a riprodurli perché non hai il contesto presente quando si è verificato l'errore.
Loguru risolve con la cattura automatica delle eccezioni e tracebacks avanzati che mostrano esattamente cosa stava succedendo nel tuo codice quando le cose sono andate storte.
Cattura automatica delle eccezioni con @logger.catch
Il decorator
@logger.catchcattura automaticamente qualsiasi eccezione che si verifichi in una funzione e la logga con tutto il contesto. I decorator come@logger.catchsono un concetto intermedio di Python che può trasformare il modo in cui gestisci gli errori in tutto il codice.Invece che il programma vada in crash con un messaggio di errore di base, Loguru cattura l'eccezione e la logga con informazioni dettagliate, mentre il programma continua a girare. Il decorator funziona su qualsiasi funzione — metodi di classe, funzioni async o funzioni normali.
Traceback avanzati con ispezione delle variabili
Ma Loguru va oltre con tracebacks avanzati che mostrano i valori delle variabili a ogni livello dello stack di chiamate. Questa funzionalità si chiama “diagnose” ed è come avere un debugger integrato nei tuoi log:
Con
diagnose=True, quando la funzione va in crash cercando di sottrarre una stringa a un numero, Loguru ti mostra esattamente cosa c'era in ogni variabile:Questo livello di dettaglio rende il debug molto più rapido perché puoi vedere esattamente quali dati hanno causato il problema.
Gestione delle eccezioni consapevole dell'ambiente
Tuttavia, i tracebacks avanzati possono esporre informazioni sensibili come password o API key nei log di produzione. Loguru ti permette di controllare questo comportamento per ambienti diversi:
Valutazione lazy per le performance
Un'altra funzione potente è la valutazione lazy, che migliora le prestazioni quando si loggano operazioni costose. A volte vuoi loggare informazioni complesse, ma solo se si verifica davvero un errore:
La sintassi
lambda:crea una funzione che viene chiamata solo quando Loguru scrive effettivamente il messaggio di log. Se non si verifica alcun errore,expensive_data_summary()non viene mai eseguita, risparmiando tempo di elaborazione.Strategie diverse per tipi di errore diversi
Puoi anche usare strategie diverse di gestione delle eccezioni per tipologie di errori diverse:
Il parametro
reraise=Falsedice a Loguru di loggare l'eccezione ma non rilanciarla, consentendo al programma di continuare. È utile per funzionalità opzionali che non dovrebbero interrompere il flusso principale.Esempio completo: elaborazione file con gestione errori
Vediamo un esempio completo con un sistema di elaborazione file che gestisce con grazia diversi tipi di errori:
Questa configurazione ti dà cattura automatica delle eccezioni, contesto di errore dettagliato quando serve e strategie diverse per tipi di errori diversi. I tuoi log diventano molto più utili per il debug, mentre il codice resta pulito e leggibile.
Configurazione e personalizzazione avanzate di Loguru
Con la crescita delle applicazioni, troverai scenari in cui i default di Loguru non bastano. Magari ti serve un livello di log speciale per metriche di business, vuoi filtrare dati sensibili dai log o devi inviare alert a Slack quando si verificano errori.
La buona notizia è che Loguru è pensato per essere personalizzato senza perdere la sua semplicità. Puoi estenderlo in modi che nei sistemi di logging tradizionali richiederebbero configurazioni complesse, mantenendo il codice pulito e leggibile.
Vediamo le personalizzazioni più utili che risolvono problemi reali che affronterai in applicazioni di produzione.
Livelli e colori personalizzati
Loguru include livelli standard come INFO, DEBUG ed ERROR. Ma a volte ti serve qualcosa di specifico per la tua applicazione. Magari vuoi un livello speciale per metriche di performance o eventi di business.
Creare livelli personalizzati è semplice:
Il parametro
noimposta la priorità del livello (numeri più alti = priorità più alta). I livelli standard usano: DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50.Vediamolo in uno scenario di training di machine learning:
Intercettare e modificare i messaggi di log
A volte devi modificare i messaggi di log prima che vengano scritti. Casi comuni includono rimuovere dati sensibili, aggiungere ID di richiesta o riformattare i messaggi per strumenti specifici.
Loguru ti permette di intercettare i messaggi usando il parametro
filter:Puoi anche usare i filtri per aggiungere informazioni contestuali:
Sink personalizzati per servizi esterni
Un sink è dove confluiscono i tuoi log. Sebbene file e console siano comuni, spesso serve inviare i log a servizi esterni come Slack, email o sistemi di monitoraggio.
Ecco come creare un sink personalizzato che invia gli errori a Slack:
Ecco un altro esempio pratico — un sink personalizzato che raccoglie metriche di performance durante l'esecuzione dell'applicazione e le salva per l'analisi:
La bellezza di questo approccio è che il codice dell'app resta pulito — logghi semplicemente le metriche normalmente e il sink collector gestisce automaticamente l'archiviazione. Puoi sostituirlo facilmente con un sink che invia metriche a Prometheus, DataDog o qualsiasi altro servizio di monitoraggio.
Queste personalizzazioni ti danno la flessibilità di adattare Loguru alle tue esigenze specifiche mantenendo la semplicità che lo rende ottimo. Che tu stia costruendo uno script piccolo o una grande applicazione, puoi estendere Loguru per gestire le tue esigenze di logging senza file di configurazione complessi o boilerplate.
Conclusione
Loguru rende il logging in Python semplice come dovrebbe essere. Niente più file di configurazione, niente più setup di handler, niente più boilerplate. Importi e inizi a loggare con colori, timestamp e rotazione automatica dei file.
Hai visto come affronta i punti dolenti comuni: salvataggio dei log su file, rotazione automatica, cattura delle eccezioni con pieno contesto e invio dei log a servizi esterni. Le funzionalità di logging strutturato lo rendono pronto per la produzione, mentre livelli e sink personalizzati ti permettono di adattarlo a qualsiasi caso d'uso.
Usa Loguru quando:
Per approfondire, esplora la documentazione ufficiale insieme a questo tutorial sul logging per una copertura completa delle strategie di logging in Python.
Inizia in piccolo. Sostituisci un'istruzione print con
logger.info(). Non tornerai indietro.