Codice Python con libreria Loguru per logging strutturato

Loguru per Python: logging strutturato, robusto e production-ready

Loguru è una libreria Python che fa sembrare il logging standard come un attrezzo del secolo scorso. In questo tutorial partiamo da zero e costruiamo un sistema di logging robusto, strutturato e sicuro per ambienti concorrenti — con rotazione compressa dei file, log asincroni, supporto multiprocesso e cattura di eccezioni. Tutto gira in un notebook Colab, ma il codice è pensato per applicazioni reali.

Dopo aver installato loguru e nest_asyncio (per eseguire codice asincrono in ambienti che già hanno un loop), prepariamo una cartella di lavoro pulita. Creiamo anche un helper check() per verificare ogni funzionalità, un global patcher che aggiunge un contatore e il campo env a ogni record, e un formatter a console che mostra timestamp, livello, modulo e messaggio. Se ci sono dati extra, li stampa in giallo.

Passiamo al cuore: la configurazione di logger.configure(). Aggiungiamo quattro handler: uno a console con colori e backtrace, uno in-memory per test, uno JSON su file structured.jsonl con serializzazione e coda asincrona, e uno per i soli errori su errors.log con formato dettagliato. Definiamo anche un livello personalizzato NOTICE (posizionato tra INFO e SUCCESS) e usiamo il patcher globale per arricchire ogni record.

Con bind() e contextualize() aggiungiamo metadati contestuali — un user_id, un request_id, o il nome di un task batch. patch() modifica il record al volo: per esempio, aggiunge un timestamp Epoch. Tutti questi dati vengono passati in automatico a ogni messaggio, senza doverli gestire manualmente nelle singole chiamate di log.

Per le eccezioni usiamo il decorator @logger.catch e il context manager logger.catch(). Il primo avvolge un’intera funzione e, se scoppia un errore (come una divisione per zero), stampa il traceback completo senza bloccare il programma. Il secondo permette di gestire eccezioni in un blocco with. Con opt(lazy=True) possiamo passare una lambda per calcoli pesanti solo se il livello di log è attivo; opt(colors=True) abilta colori inline nel messaggio; opt(record=True) ci dà accesso diretto ai campi del record.

La gestione dei file entra nel vivo con una rotazione basata sulla dimensione (ogni 1500 byte circa, per forzare la creazione di archivi). Dopo la rotazione, il file viene compresso con gzip e, se ce ne sono più di tre, i più vecchi vengono eliminati. Questo approccio è molto simile a quello che si usa in produzione per log di applicazioni web o servizi batch.

Il tutorial affronta anche la concorrenza. Con ThreadPoolExecutor e un handler in-memory per filtrare i messaggi dei thread, mostriamo come ogni worker possa scrivere log contestuali senza conflitti. Per l’asincronia, una coroutine sink raccoglie i messaggi in una lista, il logger viene usato dentro coroutine con await logger.complete() per garantire che tutto sia scritto prima di terminare. Funziona con asyncio.run() applicando nest_asyncio se necessario.

Infine, il supporto per multiprocessing viene dimostrato con un worker che scrive il proprio PID usando logger.bind(child=os.getpid()). La build-in enqueue=True (già usata in handler JSON e error) rende il logger thread-safe e multiprocess-safe senza configurazioni aggiuntive. L’interceptor InterceptHandler permette di reindirizzare verso Loguru anche le chiamate fatte con la libreria logging standard — utile quando si usano librerie di terze parti che non hanno adottato Loguru.

In sintesi: Loguru non è solo una comodità sintattica. Con poche righe si ottiene un sistema di logging strutturato, asincrono, compresso, contestuale e adatto a carichi di lavoro concorrenti. Il tutorial è completo, testabile subito su Colab e già pronto per essere adattato a progetti Python di produzione.

Articoli simili