ProgrammazioneSviluppatore backend Python

Come è strutturato il logging in Python tramite il modulo logging? Quali sono i livelli di logging esistenti e come impostare correttamente un logger in un progetto multi-modulo? Porta esempi, spiega le sottigliezze e gli errori comuni.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Il modulo logging è lo strumento standard di Python per la registrazione dei log. Implementa una gerarchia di logger e supporta i livelli di logging (severity levels): DEBUG, INFO, WARNING, ERROR, CRITICAL. Un uso corretto consente di gestire centralmente l'output, salvare log su file, inviarli per email, filtrarli per livello, ecc.

L'idea principale è creare logger con nomi (logging.getLogger(__name__)) in ogni modulo, evitando di creare un logger root globale da zero in ogni luogo. La configurazione (formato, handler, livello) viene effettuata centralmente all'avvio dell'applicazione.

Esempio di configurazione:

import logging logging.basicConfig(format='%(levelname)s:%(name)s:%(message)s', level=logging.INFO) logger = logging.getLogger(__name__) def foo(): logger.info('Messaggio informativo') logger.error('Errore!') foo()

Domanda trabocchetto.

Perché non si può chiamare logging.basicConfig() in ogni modulo? Cosa succede se lo si fa?

Risposta: logging.basicConfig() configura il logger root solo una volta per sessione Python. Le chiamate ripetute, se il logger root è già stato inizializzato, verranno ignorate. Di conseguenza, se i vari moduli tentano di chiamare basicConfig() con i propri formati/livelli, prenderà effetto solo il primo!

Esempi di errori reali dovuti all'ignoranza delle sottigliezze dell'argomento.


Storia

In un grande progetto, ogni sviluppatore configurava il logging a proprio piacimento tramite basicConfig e handler locali. A causa di ciò, alcuni log non venivano visualizzati affatto, altri venivano duplicati dieci volte e i messaggi di diversi moduli non rientravano in un unico file.


Storia

Durante la migrazione di un servizio web a un logging multilivello, si dimenticava di specificare il nome del logger tramite getLogger(__name__), si scriveva ovunque nel logger root. Di conseguenza, non era possibile determinare da dove provenisse un dato log.


Storia

Si usava la funzione logger.error() per registrare tutti i messaggi, anche quelli non errore. Di conseguenza, i sistemi di monitoraggio automatici "alzavano continuamente l'allerta", perché vedevano un alto livello di errori, anche se erano solo messaggi di debug/informativi.