Vai al contenuto principale

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.
· 10 min leggi

Scopri con l'IA

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:

pip install loguru

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 questo tutorial 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)

L'output appare nel terminale con colori, timestamp e livelli di log automaticamente. Nessun setup richiesto.

Output della console di Loguru che mostra messaggi di log colorati con timestamp e diversi livelli di log nel terminale Python

Poniamo che tu stia costruendo un semplice web scraper. Ecco come cambia il tuo debug:

import requests
from loguru import logger

def scrape_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)
       return None

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")

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")

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")

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 files

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 logs
         format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}")

def process_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")

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:

from loguru import logger

# Enable JSON structured logging
logger.add("api.log", serialize=True)

logger.info("User login", user_id=123, ip_address="192.168.1.1")
logger.error("Payment failed", user_id=123, amount=99.99, error_code="INSUFFICIENT_FUNDS")

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"}}}

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

def process_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'])

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")

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 places

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")

def register_user(email, password):
   # Create logger with user context
   user_logger = logger.bind(email=email)
  
   user_logger.info("Starting user registration")
  
   # Validate email
   if "@" not in email:
       user_logger.error("Invalid email format")
       return False
  
   # 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")
  
   return True

# Usage
register_user("[email protected]", "secure123")

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 un concetto intermedio di Python che può trasformare il modo in cui gestisci gli errori in tutto il codice.

from loguru import logger

@logger.catch
def divide_numbers(a, b):
   result = a / b
   return result

# This automatically logs the exception with full traceback
result = divide_numbers(10, 0)

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.catch
def process_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)

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"

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 information
if 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.catch
def authenticate_user(username, password, api_key):
   # In development, you'll see all variable values if this crashes
   # In production, sensitive data stays hidden
   if not username or not password:
       raise ValueError("Missing credentials")

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.catch
def process_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))
       raise

def expensive_data_summary(data):
   # This function takes time to run, summarizing huge datasets
   return {"row_count": len(data), "columns": list(data.keys()), "memory_usage": data.memory_usage()}

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")
def critical_database_operation(query):
   # Database errors get logged as ERROR level
   execute_database_query(query)

@logger.catch(level="WARNING", reraise=False)
def optional_feature(user_id):
   # Non-critical features log as WARNING and continue execution
   send_optional_notification(user_id)

def process_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)

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 logging
if 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)
def validate_file_format(filename):
   if not filename.endswith(('.csv', '.json', '.xml')):
       raise ValueError(f"Unsupported file format: {filename}")

@logger.catch
def load_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)})
  
   with open(filename, 'r') as f:
       return f.read()

def process_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)
           continue
  
   return results

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")

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")

def train_model(model, data_loader, epochs=10):
   logger.info("Starting training with {} epochs", epochs)
  
   for epoch in range(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 epochs
       if (epoch + 1) % 5 == 0:
           logger.log("CHECKPOINT", "Model saved at epoch {}", epoch + 1)
  
   logger.success("Training completed!")

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

def hide_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 log
   return True

# 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]")

Puoi anche usare i filtri per aggiungere informazioni contestuali:

from loguru import logger
import threading

def add_thread_info(record):
   # Add thread name to every log message
   record["extra"]["thread_name"] = threading.current_thread().name
   return True

def add_environment_info(record):
   # Add environment to production logs
   record["extra"]["env"] = "production"
   record["extra"]["region"] = "us-west-2"
   return True

# 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}"
)

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

def send_to_slack(message):
   """Custom sink that sends messages to Slack"""
   # Parse the log record
   record = message.record
  
   # Only send errors and above
   if record["level"].no < 40:  # ERROR level is 40
       return
  
   # 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!")

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

class MetricsCollector:
   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 logs
       if 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()
           })
  
   def save_metrics(self):
       """Save all collected metrics to a JSON file"""
       with open("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...}
#   ]
# }

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

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.

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.

Bexruz (Bex) Tuychiev

Autore

Bexruz (Bex) Tuychiev

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. 

Argomenti

Correlato