Post Image

Gli handler dei log in Python, presenti all'interno del modulo logging, rappresentano una parte fondamentale della libreria. Gli handler sono utilizzati per gestire l'output dei messaggi dei log. Gli handler determinano dove e come i messaggi dei log vengono inviati.

Un logger può avere associato a se un numero indefinito di handler. Alla scrittura di un messaggio di log, ogni handler si occupa di capire se il messaggio è di sua competenza e a chi deve inviarlo.

Ad ogni nuovo messaggio di log inviato su un logger, ogni handler verifica se il messaggio ha un livello adeguato del log e successivamente, se il livello è soddisfatto, spedisce il messaggio alla destinazione stabilita.

Il modulo di logging offre una molteplicità di handler predefiniti che soddisfano la maggior parte delle esigenze degli sviluppatori. In questo articolo vedrai un elenco degli handler a disposizione con una spiegazione del funzionamento di ciascuno.

Prerequisiti

Per la lettura del seguente articolo è opportuno che tu abbia conoscenza del logging in Python e di cosa sono i livelli di log. Per studiare o ripassare questi argomenti puoi leggere gli articoli, Guida Completa al Logging in Python dalla Configurazione di Base alla Configurazione Avanzata e Livelli di Log in Python: Tutto Quello che Devi Sapere per un Logging Efficace.

StreamHandler

Uno StreamHandler invia i messaggi di log ad uno stream. Il caso più comune è l'invio alla console sys.stdout e sys.stderr, che nei sistemi Unix-like sono le console predefinite per lo StandardOutput e StandardError.

Ogni messaggio scritto sul logger sarà inviato dall'handler sulla console, a patto che il livello di log definito sia rispettato.

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
logger.addHandler(handler)

logger.debug("pippo")

Nel precedente esempio, l'handler stampa su console il messaggio pippo.

FileHandler

Un FileHandler invia i messaggi di log ad un file. Questo handler consente quindi la scrittura dei messaggi su un file prestabilito. Questo tipo di handler molto utile poiché in qualsiasi momento consente allo sviluppatore di capire se il software sta o meno funzionando.

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

handler = logging.FileHandler('filehandler.log')
logger.addHandler(handler)

logger.debug("pippo")

La sintassi è molto simile allo StreamHandler, cambia solo la classe con la quale creare l'oggetto.

RotatingFileHandler

Il RotatingFileHandler invia e scrive i messaggi di log su file, così come avviene nel FileHandler, ma aggiunge il supporto alla rotazione dei file, quando raggiungono una dimensione specificata.

Il funzionamento prevede che all'arrivo dei messaggi di log, l'handler prima di scrivere il messaggio sul file controlla in primo luogo se il livello di log è consentito ed in secondo luogo se la dimensione del file di log consente la scrittura del messaggio; se la dimensione è consentita, allora scrive il messaggio nel file di log, altrimenti crea un nuovo file all'interno del quale scrive il messaggio. Contestualmente alla creazione del nuovo file di log, tutti i file precedenti vengono ruotati ossia vengono rinominati con un suffisso numerico che è incrementato di uno.

Dato il seguente frammento di codice:

import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = RotatingFileHandler('filehandler.log', maxBytes=1024, backupCount=5)
logger.addHandler(handler)
logger.debug("Prova Rotating File Handler")

il file di log si chiama filehandler.log. Ad ogni rotazione il file di log sul quale l'handler scrive è sempre lo stesso, ma le rotazioni creano i file con i nomi: filehandler.log.1, filehandler.log.2 e così via per un numero massimo imposto dal parametro backupCount.

I parametri inviati all'oggetto RotatingFileHandler sono:

  • nomefile
  • maxBytes: dimensione massima del file di log (oltre la quale il file sarà ruotato)
  • backupCount: numero di file di backup

TimedRotatingFileHandler

Questo handler ha lo stesso comportamento del RotatingFileHandler con la differenza che la rotazione dei file avviene su intervalli temporali piuttosto che sulla dimensione dei file.

Supponiamo il seguente esempio:

import logging
from logging.handlers import TimedRotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = TimedRotatingFileHandler(
    'filehandler.log', when='midnight', interval=1
)
logger.addHandler(handler)
logger.debug("Prova Rotating File Handler")

La rotazione dei log avviene tutte le sere a mezzanotte a prescindere dalla dimensione dei file.

SMTPHandler

L'handler invia i messaggi di log tramite per email. Questo handler è molto utile per gli amministratori di sistema poiché possono essere avvertiti tramite email che è avvenuto qualche grave malfunzionamento.

import logging
from logging.handlers import SMTPHandler
logger = logging.getLogger(__name__)
handler = SMTPHandler(mailhost=('smtp.example.com', 587),
                      fromaddr='from@example.com',
                      toaddrs=['to@example.com'],
                      subject='Log Message',
                      credentials=('username', 'password'),
                      secure=())
handler.setLevel(logging.ERROR)
logger.addHandler(handler)

Il precedente esempio mostra chiaramente la necessità di impostare i parametri per l'invio della mail, ed inoltre mostra che l'handler lavora solo con messaggi con livello di log minimo pari a ERROR.

HTTPHandler

L'HTTPHandler invia i messaggi di log ad un server web tramite richieste HTTP POST o HTTP GET. Questo handler è utile quando si ha necessità di centralizzare la gestione dei log su un sistema remoto o quando si devono integrare i propri log con sistemi di terze parti.

import logging
from logging.handlers import HTTPHandler
logger = logging.getLogger(__name__)
handler = HTTPHandler('www.example.com', '/log', method='POST')
logger.addHandler(handler)

SysLogHandler

Il SysLogHandler invia i messaggi ad un syslog server. Per utilizzare questo handler occorre che sia installato e configurato un server syslog.

import logging
from logging.handlers import SysLogHandler
logger = logging.getLogger(__name__)
handler = SysLogHandler(address='/dev/log')
logger.addHandler(handler)

SockerHandler

Il SocketHandler invia i messaggi tramite socket. Questo handlerè utile quando hai bisogno di inviare i log ad un server remoto tramite socket TCP o UDP.

Questo handler è molto flessibile e può essere utilizzato per integrare il logging in applicazioni distribuite o per inviare i log a un sistema di logging centralizzato.

import logging
from logging.handlers import SocketHandler
logger = logging.getLogger(__name__)
handler = SocketHandler('localhost', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
logger.addHandler(handler)

QueueHandler

Il QueueHandler invia i messaggi tramite coda. I messaggi possono essere gestiti sia con scrittura su file sia su console. L'approccio seguito dall'handler è quello di inviare i messaggi ad una coda che si occupa di inviare gli stessi ad altri handler per la scrittura.

Il processo di scrittura è perfettamente asincrono e pertanto questo tipo di log non impatta le performance applicative.

import logging
from logging.handlers import QueueHandler
import queue
log_queue = queue.Queue()
logger = logging.getLogger(__name__)
handler = QueueHandler(log_queue)
logger.addHandler(handler)

Conclusioni

Gli handler dei log in Python offrono una flessibilità significativa per indirizzare i messaggi di log in diverse destinazioni. Comprendere come configurare e utilizzare questi handler ti permette di creare applicazioni robuste con una gestione efficace dei log.

In questo articolo hai visto gli handler messi a disposizione dal modulo Python. Potrai utilizzare questi handler all'interno dei tuoi progetti per gestire al meglio il tuo software.