SXXXXXXX_ControlPanel/controlpanel/logging_config.py
2025-05-06 11:18:50 +02:00

261 lines
11 KiB
Python

# logging_config.py
"""
THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Configures logging for the application.
Includes a custom filter (DebugControlFilter) to control DEBUG messages based on
flags in the config module, and a setup function (setup_logging) to configure
the root logger, handlers, formatters, and apply the filter.
"""
# Standard library imports
import logging
import sys
# Local application imports
from controlpanel import config # For DEBUG flags and logging levels
# --- Custom Logging Filter ---
class DebugControlFilter(logging.Filter):
"""
Filters log messages based on level and specific DEBUG flags in `config`.
Allows all messages with level > DEBUG.
Filters DEBUG messages based on message prefixes and corresponding
boolean flags defined in the `config` module.
"""
def filter(self, record):
"""
Determines if the specified log record should be processed.
Args:
record (logging.LogRecord): The log record to check.
Returns:
bool: True if the record should be logged, False otherwise.
"""
# Allow levels higher than DEBUG unconditionally
if record.levelno > logging.DEBUG:
return True
# Block levels lower than DEBUG (shouldn't happen if root is DEBUG)
if record.levelno < logging.DEBUG:
return False
# --- Filter DEBUG messages based on prefixes and config flags ---
if record.levelno == logging.DEBUG:
msg = record.getMessage() # Get the formatted message content
# Check Map related prefixes first
map_prefixes = (
"[Map", # Cattura [MapTileManager], [MapIntegrationManager], [MapUtils], [MapService], [MapDisplay]
# Aggiungi altri prefissi specifici se necessario (es. da helper interni)
)
if msg.startswith(map_prefixes):
# Se il messaggio inizia con un prefisso mappa E il flag è True, mostralo
if config.DEBUG_MAP_DETAILS:
return True
else:
# Altrimenti, se il flag è False, blocca questo messaggio DEBUG mappa
return False
# Check prefixes against corresponding config flags
# App General & Lifecycle
if msg.startswith("[App Init]") and config.DEBUG_APP_LIFECYCLE:
return True
elif msg.startswith("[ImageRecorder") and config.DEBUG_IMAGE_RECORDER:
return True # Allow if ImageRecorder prefix and flag is True
elif msg.startswith("[App Shutdown]") and config.DEBUG_APP_LIFECYCLE:
return True
elif msg.startswith("[App Status]") and config.DEBUG_APP_STATUS:
return True
elif msg.startswith("[AppState") and config.DEBUG_APP_LIFECYCLE:
return True # AppState logs
elif msg.startswith("[App MainThread") and config.DEBUG_APP_LIFECYCLE:
return True # Main thread processing logs
# App Callbacks & Processing
elif msg.startswith("[App CB") and config.DEBUG_APP_CALLBACKS:
if msg.startswith("[App CB MFD Param]") and config.DEBUG_APP_MFD_PARAMS:
return True
elif not msg.startswith("[App CB MFD Param]"):
return True # Allow general CB if not MFD specific
elif msg.startswith("[App QProc") and config.DEBUG_APP_QUEUE_PROCESSING:
return True
elif msg.startswith("[App Proc") and config.DEBUG_APP_IMG_PROCESSING:
return True
# App Specific Features
elif msg.startswith("[App Test") and config.DEBUG_APP_TEST_MODE:
return True
elif msg.startswith("[App GeoCalc]") and config.DEBUG_APP_GEO_CALC:
return True
elif msg.startswith("[MFD LUT Update]") and config.DEBUG_APP_MFD_PARAMS:
return True
elif msg.startswith("[App Trigger") and config.DEBUG_APP_TRIGGER:
return True
# Map related App logs
elif msg.startswith("[App Init Map") and config.DEBUG_APP_LIFECYCLE:
return True
elif msg.startswith("[App Map Update]") and config.DEBUG_APP_LIFECYCLE:
return True
# Receiver Related
elif msg.startswith("[Receiver Loop]") and config.DEBUG_RECEIVER_LOOP:
return True
elif msg.startswith("[Receiver ACK]") and config.DEBUG_RECEIVER_ACK:
return True
elif msg.startswith("[Receiver Cleanup]") and config.DEBUG_RECEIVER_CLEANUP:
return True
elif "Rcvd: Key=" in msg and config.DEBUG_RECEIVER_PACKETS:
return True # Raw packet header
elif (
msg.startswith("[Worker")
or msg.startswith("[Receiver Reassembly]")
or "Reassembling" in msg
or "Identified" in msg
or "reassemble" in msg.lower()
or "New TX" in msg
or "All frags" in msg
or "Cleaned Key=" in msg
or "Submit" in msg
or "pixel data offset" in msg
or "cleanup" in msg.lower()
) and config.DEBUG_RECEIVER_REASSEMBLY:
return True # Reassembly logs
elif (
msg.startswith("[Geo extract]")
or "GeoInfo:" in msg
or "Invalid GeoInfo" in msg
or "Invalid SAR meta" in msg
or "Invalid MFD meta" in msg
or "GeoData extraction" in msg
) and config.DEBUG_RECEIVER_GEO:
return True # Geo extraction logs
# Display/UI Related
elif msg.startswith("[DisplayMgr]") and config.DEBUG_DISPLAY_MANAGER:
return True
elif msg.startswith("[MapDisplay]") and config.DEBUG_DISPLAY_MANAGER:
return True
elif msg.startswith("[UI Setup]") and config.DEBUG_APP_LIFECYCLE:
return True # UI creation logs
elif msg.startswith("[UI Update]") and config.DEBUG_APP_CALLBACKS:
return True # General UI updates
elif msg.startswith("[UI Status]") and config.DEBUG_APP_STATUS:
return True # Status bar updates
# Utility Modules
elif msg.startswith("[Utils") and config.DEBUG_UTILS:
return True
elif msg.startswith("[Network") and config.DEBUG_NETWORK:
return True
elif msg.startswith("[ImageProcessing") and config.DEBUG_IMAGE_PROCESSING:
return True
elif msg.startswith("[MapUtils") and config.DEBUG_UTILS:
return True
elif msg.startswith("[MapTileManager") and config.DEBUG_UTILS:
return True
elif msg.startswith("[MapService") and config.DEBUG_UTILS:
return True
# Default: Block DEBUG message if no specific flag allows it
return False
# Should not be reached if handler level > DEBUG, but return False defensively
return False
# --- Logging Setup Function ---
def setup_logging():
"""Configures the root logger for the application using DebugControlFilter."""
log_prefix = "[Log Setup]" # Prefix for this function's messages
# Check if logging is already configured (simple check based on handlers)
root_logger = logging.getLogger()
if root_logger.hasHandlers():
# Check if our specific handler/filter is already present
has_our_filter = any(
isinstance(f, DebugControlFilter)
for h in root_logger.handlers
for f in h.filters
)
if has_our_filter:
logging.debug(
f"{log_prefix} Logging seems already configured with DebugControlFilter. Skipping setup."
)
return # Avoid re-configuring if already done
# Include thread name in the log format
log_format = "%(asctime)s - %(levelname)s - [%(threadName)s] - %(filename)s:%(lineno)d - %(message)s"
log_formatter = logging.Formatter(log_format)
# Re-configure root logger if needed (e.g., level changed)
# Ensure root level is low enough to allow filter to work on DEBUG messages
root_logger.setLevel(config.LOG_ROOT_LEVEL)
# Remove existing handlers before adding new ones to prevent duplication
# (More robust reconfiguration)
# Use print here as logging might be in an intermediate state
if root_logger.handlers:
print(
f"{log_prefix} Removing existing logging handlers before reconfiguration."
)
for handler in root_logger.handlers[:]: # Iterate over a copy
root_logger.removeHandler(handler)
handler.close() # Close the handler properly
# Configure console handler
# Use stderr by default for logs? Or keep stdout? Default is stderr for StreamHandler.
console_handler = logging.StreamHandler(
sys.stdout
) # Explicitly use stdout for visibility? Or stderr?
console_handler.setLevel(config.LOG_HANDLER_LEVEL) # Use level from config
console_handler.setFormatter(log_formatter)
# Add custom filter
debug_filter = DebugControlFilter()
console_handler.addFilter(debug_filter)
# Add the configured handler to the root logger
root_logger.addHandler(console_handler)
# Use INFO level for confirmation messages after setup
logging.info(f"{log_prefix} Console log handler added and configured.")
logging.info(
f"{log_prefix} Logging configured: Root Level={logging.getLevelName(root_logger.level)}, "
f"Handler Level={logging.getLevelName(console_handler.level)}"
)
# Log status of all current debug flags
log_flags_status = (
f"{log_prefix} Debug Flags: Rcv["
f"Pkt:{config.DEBUG_RECEIVER_PACKETS},"
f"Rsm:{config.DEBUG_RECEIVER_REASSEMBLY},"
f"Geo:{config.DEBUG_RECEIVER_GEO},"
f"Loop:{config.DEBUG_RECEIVER_LOOP},"
f"Ack:{config.DEBUG_RECEIVER_ACK},"
f"Cln:{config.DEBUG_RECEIVER_CLEANUP}], "
f"App["
f"Life:{config.DEBUG_APP_LIFECYCLE},"
f"CB:{config.DEBUG_APP_CALLBACKS},"
f"Q:{config.DEBUG_APP_QUEUE_PROCESSING},"
f"Proc:{config.DEBUG_APP_IMG_PROCESSING},"
f"Test:{config.DEBUG_APP_TEST_MODE},"
f"GeoCalc:{config.DEBUG_APP_GEO_CALC},"
f"MFDParam:{config.DEBUG_APP_MFD_PARAMS},"
f"Stat:{config.DEBUG_APP_STATUS},"
f"Trig:{config.DEBUG_APP_TRIGGER}], "
f"Disp:{config.DEBUG_DISPLAY_MANAGER}, "
f"Map:{config.DEBUG_MAP_DETAILS}, "
f"Util:{config.DEBUG_UTILS}, "
f"Net:{config.DEBUG_NETWORK}, "
f"ImgProc:{config.DEBUG_IMAGE_PROCESSING}, "
f"ImgRec:{config.DEBUG_IMAGE_RECORDER}"
"]"
)
logging.info(log_flags_status)