151 lines
6.7 KiB
Python
151 lines
6.7 KiB
Python
# --- FILE: gitsync_tool/logging_setup/logger_config.py ---
|
|
|
|
import logging
|
|
import os
|
|
import sys # Per fallback print su stderr
|
|
from typing import Dict, Optional # Aggiunti type hints
|
|
|
|
# --- Costanti Condivise ---
|
|
# Nome del file di log (potrebbe essere importato da un file di costanti globali se preferito)
|
|
LOG_FILE: str = "git_sync_tool.log"
|
|
# Formato standard per i messaggi di log scritti nel file
|
|
LOG_FORMAT: str = (
|
|
"%(asctime)s - %(levelname)-8s - [%(name)s:%(funcName)s] - %(message)s"
|
|
)
|
|
# Formato per data/ora nel file di log
|
|
LOG_DATE_FORMAT: str = "%Y-%m-%d %H:%M:%S"
|
|
|
|
# Mappa Livelli (Opzionale qui, ma utile se si usa get_log_level_name)
|
|
LOG_LEVEL_MAP: Dict[int, str] = {
|
|
logging.CRITICAL: "CRITICAL",
|
|
logging.ERROR: "ERROR",
|
|
logging.WARNING: "WARNING",
|
|
logging.INFO: "INFO",
|
|
logging.DEBUG: "DEBUG",
|
|
logging.NOTSET: "NOTSET",
|
|
}
|
|
|
|
|
|
def get_log_level_name(level_number: int) -> str:
|
|
"""Restituisce il nome stringa leggibile per un livello di logging numerico."""
|
|
return LOG_LEVEL_MAP.get(level_number, f"LEVEL_{level_number}")
|
|
|
|
|
|
def setup_file_logging(level: int = logging.INFO) -> None:
|
|
"""
|
|
Configures the root logger to write log messages to a file.
|
|
|
|
Questa funzione aggiunge un FileHandler configurato al logger root di Python.
|
|
Tutti i messaggi di log inviati tramite il modulo standard `logging`
|
|
(con livello uguale o superiore a quello impostato qui e sul root logger)
|
|
verranno scritti su questo file.
|
|
|
|
Args:
|
|
level (int): Il livello minimo di log da catturare e scrivere
|
|
nel file (es. logging.INFO, logging.DEBUG).
|
|
Default è logging.INFO.
|
|
"""
|
|
func_name: str = "setup_file_logging" # Nome per log interni (se necessario)
|
|
try:
|
|
# 1. Crea il Formatter per i messaggi nel file
|
|
log_formatter = logging.Formatter(LOG_FORMAT, datefmt=LOG_DATE_FORMAT)
|
|
|
|
# 2. Configura il File Handler
|
|
# mode='a': Accoda i log al file esistente ad ogni avvio.
|
|
# encoding='utf-8': Usa UTF-8 per supportare caratteri internazionali.
|
|
log_file_path: str = os.path.abspath(LOG_FILE) # Ottieni percorso assoluto
|
|
file_handler = logging.FileHandler(log_file_path, mode="a", encoding="utf-8")
|
|
file_handler.setLevel(level) # Imposta il livello MINIMO per QUESTO handler
|
|
file_handler.setFormatter(log_formatter) # Applica il formattatore
|
|
|
|
# 3. Ottieni il Root Logger
|
|
# Configurare il root logger è il modo standard per avere un logging
|
|
# di base per l'intera applicazione.
|
|
root_logger = logging.getLogger()
|
|
|
|
# 4. (Opzionale ma Consigliato) Rimuovi handler file preesistenti per lo stesso file
|
|
# Questo previene la duplicazione dei log se setup_file_logging
|
|
# viene chiamato accidentalmente più volte.
|
|
handler_removed: bool = False
|
|
for handler in root_logger.handlers[:]: # Itera su una copia della lista
|
|
if isinstance(handler, logging.FileHandler):
|
|
# Controlla se l'handler punta allo stesso file
|
|
# Nota: handler.baseFilename potrebbe essere None se non ancora usato
|
|
try:
|
|
# Confronta percorsi assoluti normalizzati
|
|
current_handler_path = getattr(handler, "baseFilename", None)
|
|
if current_handler_path and os.path.normcase(
|
|
current_handler_path
|
|
) == os.path.normcase(log_file_path):
|
|
root_logger.removeHandler(handler)
|
|
handler.close() # Chiudi l'handler prima di rimuoverlo
|
|
handler_removed = True
|
|
print(
|
|
f"INFO: Removed pre-existing file handler for: {log_file_path}"
|
|
) # Usa print qui
|
|
except Exception as e_rm:
|
|
# Logga avviso se il controllo/rimozione fallisce
|
|
print(
|
|
f"WARNING: Could not check/remove existing file handler: {e_rm}",
|
|
file=sys.stderr,
|
|
)
|
|
|
|
# 5. Aggiungi il nuovo File Handler al Root Logger
|
|
root_logger.addHandler(file_handler)
|
|
|
|
# 6. Imposta il Livello del Root Logger
|
|
# Il root logger deve avere un livello uguale o *inferiore* a quello
|
|
# dell'handler affinché i messaggi raggiungano l'handler.
|
|
# Impostarlo al livello più basso tra quelli degli handler configurati
|
|
# (o DEBUG se si vuole massima flessibilità) è una buona pratica.
|
|
# Qui lo impostiamo almeno al livello richiesto per il file handler.
|
|
if root_logger.level == logging.NOTSET or root_logger.level > level:
|
|
root_logger.setLevel(level)
|
|
print(f"INFO: Root logger level set to: {get_log_level_name(level)}")
|
|
|
|
# 7. Log di Conferma (su console e nel file stesso)
|
|
log_level_name: str = get_log_level_name(level)
|
|
confirmation_message: str = (
|
|
f"File logging configured. Minimum level for file '{LOG_FILE}': {log_level_name}. "
|
|
f"Path: {log_file_path}"
|
|
)
|
|
print(f"INFO: {confirmation_message}") # Conferma su console
|
|
# Scrive un messaggio nel file di log appena configurato
|
|
logging.info(f"--- File logging initialized (Level: {log_level_name}) ---")
|
|
if handler_removed:
|
|
logging.warning(
|
|
"Removed pre-existing file handler pointing to the same log file."
|
|
)
|
|
|
|
except Exception as e:
|
|
# Fallback critico in caso di errore nella configurazione del logging
|
|
error_message: str = (
|
|
f"CRITICAL: Failed to set up file logging for '{LOG_FILE}': {e}"
|
|
)
|
|
print(error_message, file=sys.stderr)
|
|
# Tenta di usare basicConfig come ultima risorsa per loggare l'errore su console
|
|
try:
|
|
logging.basicConfig(level=logging.ERROR)
|
|
logging.critical(error_message, exc_info=True)
|
|
except Exception:
|
|
pass # Ignora errori in basicConfig
|
|
|
|
|
|
# Esempio di utilizzo (non eseguito quando importato)
|
|
if __name__ == "__main__":
|
|
print("Setting up file logging with DEBUG level...")
|
|
setup_file_logging(level=logging.DEBUG)
|
|
print(f"File logging configured. Check the file: '{LOG_FILE}'")
|
|
|
|
# Esempi di log che dovrebbero apparire nel file
|
|
logging.debug("This is a debug message for the file.")
|
|
logging.info("This is an info message for the file.")
|
|
logging.warning("This is a warning message for the file.")
|
|
logging.error("This is an error message for the file.")
|
|
|
|
# Puoi anche ottenere un logger specifico e usarlo
|
|
test_logger = logging.getLogger("MyTestModule")
|
|
test_logger.info("Message from test_logger.")
|
|
|
|
# --- END OF FILE gitsync_tool/logging_setup/logger_config.py ---
|