# --- 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 ---