SXXXXXXX_GitUtility/log_handler.py

147 lines
5.2 KiB
Python

# --- START OF FILE log_handler.py ---
import queue
import logging
import datetime
import traceback # Per log_exception
import sys # Per log_exception su stderr
# Coda condivisa thread-safe per i messaggi di log
# Usiamo una Queue standard, che è illimitata per default.
# Se si teme un consumo eccessivo di memoria in scenari estremi,
# si potrebbe usare maxsize, ma di solito non è necessario per i log.
log_queue = queue.Queue()
# Mappa livelli di logging numerici a nomi stringa per chiarezza nell'output
# Ricalca quella definita (ora rimossa) da logger_config.py
LOG_LEVEL_MAP = {
logging.CRITICAL: "CRITICAL",
logging.ERROR: "ERROR",
logging.WARNING: "WARNING",
logging.INFO: "INFO",
logging.DEBUG: "DEBUG",
logging.NOTSET: "NOTSET",
}
def get_log_level_name(level_no):
"""Restituisce il nome stringa leggibile per un livello di logging numerico."""
# Usa la mappa, con un fallback per livelli non standard
return LOG_LEVEL_MAP.get(level_no, f"LEVEL_{level_no}")
def _format_log_message(level, message, func_name):
"""
Funzione interna per formattare il messaggio di log.
Separa la formattazione dalla logica di accodamento.
"""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
level_name = get_log_level_name(level)
# Includi il nome della funzione solo se fornito
func_part = f" [{func_name}]" if func_name else ""
# Formato standard: Timestamp - LEVEL - [FuncName] - Messaggio
formatted_message = f"{timestamp} - {level_name} -{func_part} - {message}"
return formatted_message
def log_message(level, message, func_name=""):
"""
Formatta un messaggio di log e lo mette nella coda condivisa 'log_queue'.
Args:
level (int): Il livello di logging numerico (es. logging.INFO).
message (str): Il messaggio da loggare.
func_name (str, optional): Nome della funzione chiamante (per contesto).
"""
# Formatta il messaggio
formatted_message = _format_log_message(level, message, func_name)
# Crea il dizionario da mettere in coda
# Include sia il messaggio formattato che il livello numerico originale
# (utile per il processore della coda per filtrare o colorare).
log_entry = {"level": level, "message": formatted_message}
try:
# Metti l'entry nella coda senza bloccare (put_nowait)
log_queue.put_nowait(log_entry)
except queue.Full:
# Gestione fallback se la coda fosse piena (improbabile)
# Stampa direttamente su stderr per non perdere il messaggio critico
print(
f"!!! LOG QUEUE FULL - Dropping message: {formatted_message}",
file=sys.stderr,
)
except Exception as e:
# Gestione di altri errori imprevisti durante l'accodamento
print(
f"!!! ERROR putting message in log queue: {e} - Message: {formatted_message}",
file=sys.stderr,
)
# --- Funzioni Helper per Livelli Specifici ---
# Queste rendono il codice chiamante più pulito (es. log_handler.log_info(...) )
def log_debug(message, func_name=""):
"""Invia un messaggio di livello DEBUG alla coda log."""
log_message(logging.DEBUG, message, func_name)
def log_info(message, func_name=""):
"""Invia un messaggio di livello INFO alla coda log."""
log_message(logging.INFO, message, func_name)
def log_warning(message, func_name=""):
"""Invia un messaggio di livello WARNING alla coda log."""
log_message(logging.WARNING, message, func_name)
def log_error(message, func_name=""):
"""Invia un messaggio di livello ERROR alla coda log."""
log_message(logging.ERROR, message, func_name)
def log_critical(message, func_name=""):
"""Invia un messaggio di livello CRITICAL alla coda log."""
log_message(logging.CRITICAL, message, func_name)
def log_exception(message, func_name=""):
"""
Invia un messaggio di livello ERROR per un'eccezione e stampa
il traceback sulla console/stderr.
"""
# Logga un messaggio generico nella coda, indicando di controllare altrove
error_msg = f"{message} (See console/stderr for traceback)"
log_message(logging.ERROR, error_msg, func_name)
# Stampa il traceback completo su stderr per diagnostica immediata
# Questo NON va nella coda log GUI/File, solo sulla console da cui è
# stata lanciata l'applicazione (o dove viene reindirizzato stderr).
print(f"--- EXCEPTION TRACEBACK ({func_name}) ---", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
print(f"--- END TRACEBACK ---", file=sys.stderr)
# Esempio di utilizzo (non eseguito quando importato):
if __name__ == "__main__":
print("Esempio di utilizzo del log_handler (messaggi vanno in coda):")
log_info("Questo è un messaggio informativo.", func_name="esempio")
log_debug("Questo è un messaggio di debug.", func_name="esempio")
try:
x = 1 / 0
except ZeroDivisionError:
log_exception(
"Si è verificato un errore durante il calcolo.", func_name="esempio_errore"
)
print(f"Dimensione attuale della coda log: {log_queue.qsize()}")
print("Recupero messaggi dalla coda:")
while not log_queue.empty():
entry = log_queue.get()
print(f" Livello: {entry['level']}, Messaggio: {entry['message']}")
# --- END OF FILE log_handler.py ---