浏览代码

ref: refactor logging setup and improve logger initialization in multiple modules

Silas Gruen 6 月之前
父节点
当前提交
1cb7a5b799
共有 4 个文件被更改,包括 44 次插入57 次删除
  1. 2 5
      main.py
  2. 2 2
      robot_control/src/api/grbl_handler.py
  3. 0 5
      robot_control/src/robot/pump_controller.py
  4. 40 45
      robot_control/src/utils/logging.py

+ 2 - 5
main.py

@@ -7,15 +7,12 @@ from robot_control.src.api.i2c_handler import I2C, MockI2C
 from robot_control.src.vendor.mcp3428 import MCP3428
 from robot_control.src.robot.pump_controller import PumpController
 from robot_control.src.api.gpio import PiGPIO, MockGPIO
-
-logging.basicConfig(
-    level=logging.INFO,
-    format='%(asctime)s - %(module)s - %(levelname)s - %(message)s',
-)
+from robot_control.src.utils.logging import setup_logging
 
 class LoaderSystem:
     def __init__(self):
         self.config = ConfigParser().config
+        setup_logging(self.config)
         gpio_config = self.config.gpio
         if gpio_config.debug:
             self.gpio = MockGPIO()

+ 2 - 2
robot_control/src/api/grbl_handler.py

@@ -5,14 +5,14 @@ import logging
 import datetime
 import collections
 
+logger = logging.getLogger(__name__)
+
 MOVE_RATE = 50
 APPROACHE_RATE = 10 
 CELL_CIRCLE_RADIUS = 0.35
 
 HOMING_TIMEOUT_S = 80
 
-logger = logging.getLogger(__name__)
-
 class GRBLHandler:
     def __init__(self, port: str, baudrate: int):
         self.port = port

+ 0 - 5
robot_control/src/robot/pump_controller.py

@@ -3,11 +3,6 @@ from robot_control.src.utils.config import RobotConfig
 from robot_control.src.api.gpio import GPIOInterface
 import logging
 
-logging.basicConfig(
-    level=logging.DEBUG,
-    format='%(asctime)s - %(module)s - %(levelname)s - %(message)s',
-)
-
 logger = logging.getLogger(__name__)
 
 class PumpController:

+ 40 - 45
robot_control/src/utils/logging.py

@@ -1,58 +1,58 @@
 import logging
 from logging.handlers import RotatingFileHandler
 import os
-from typing import Optional
 from .config import RobotConfig
-import time
 
 THROTTLING_FILTER_ENABLED = False
 
-# TODO [SG]: Currently not used due to multiple problems:
-# No individual logger naming for each module
-# Throttling filtered too much
-# Coul not be created without config
-
-class LoggerSingleton:
-    _instance: Optional[logging.Logger] = None
+# Usage:
+# In main.py, after loading config:
+#   from robot_control.src.utils.logging import setup_logging
+#   setup_logging(config)
+# In each module:
+#   import logging
+#   logger = logging.getLogger(__name__)
+#   logger.info("message")
 
-    @classmethod
-    def get_logger(cls, config: Optional[RobotConfig] = None) -> logging.Logger:
-        # if config is None:
-        #     config = RobotConfig()
-        if cls._instance is None and config is not None:
-            cls._instance = cls._setup_logger(config)
-        return cls._instance
+def setup_logging(config: RobotConfig):
+    """
+    Set up logging configuration globally using the provided config.
+    Should be called once at program startup (e.g., in main.py).
+    """
+    log_config = config.logging
+    log_level = getattr(logging, log_config.level)
+    os.makedirs(os.path.dirname(log_config.file_path), exist_ok=True)
 
-    @staticmethod
-    def _setup_logger(config: RobotConfig) -> logging.Logger:
-        log_config = config.logging
-        logger = logging.getLogger('robot_control')
-        logger.setLevel(getattr(logging, log_config.level))
+    # Remove all handlers associated with the root logger object.
+    for handler in logging.root.handlers[:]:
+        logging.root.removeHandler(handler)
 
-        os.makedirs(os.path.dirname(log_config.file_path), exist_ok=True)
+    handlers = []
+    # File handler
+    file_handler = RotatingFileHandler(
+        log_config.file_path,
+        maxBytes=log_config.max_file_size_mb * 1024 * 1024,
+        backupCount=log_config.backup_count
+    )
+    file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    if THROTTLING_FILTER_ENABLED:
+        file_handler.addFilter(ThrottlingFilter())
+    file_handler.setFormatter(file_formatter)
+    handlers.append(file_handler)
 
-        file_handler = RotatingFileHandler(
-            log_config.file_path,
-            maxBytes=log_config.max_file_size_mb * 1024 * 1024,
-            backupCount=log_config.backup_count
-        )
-        file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+    # Console handler
+    if log_config.console_output:
+        console_handler = logging.StreamHandler()
         if THROTTLING_FILTER_ENABLED:
-            file_handler.addFilter(ThrottlingFilter())
-        file_handler.setFormatter(file_formatter)
-        logger.addHandler(file_handler)
+            console_handler.addFilter(ThrottlingFilter())
+        console_formatter = logging.Formatter('%(levelname)s: %(name)s: %(message)s')
+        console_handler.setFormatter(console_formatter)
+        handlers.append(console_handler)
 
-        if log_config.console_output:
-            console_handler = logging.StreamHandler()
-            if THROTTLING_FILTER_ENABLED:
-                console_handler.addFilter(ThrottlingFilter())
-            console_formatter = logging.Formatter('%(levelname)s: %(message)s')
-            console_handler.setFormatter(console_formatter)
-            logger.addHandler(console_handler)
-
-        return logger
+    logging.basicConfig(level=log_level, handlers=handlers)
 
 
+import time
 class ThrottlingFilter(logging.Filter):
     def __init__(self, name='', initial_throttle_interval=1.0, max_throttle_interval=120.0, 
                  throttle_multiplier=2.0, reset_after=120.0):
@@ -73,17 +73,14 @@ class ThrottlingFilter(logging.Filter):
     def filter(self, record):
         current_time = time.time()
         message_key = record.getMessage()
-        
         if message_key not in self.message_states:
             self.message_states[message_key] = {
                 'last_time': current_time,
                 'current_interval': self.initial_throttle_interval
             }
             return True
-        
         state = self.message_states[message_key]
         time_since_last = current_time - state['last_time']
-        
         # Reset throttle interval if message hasn't been seen for reset_after seconds
         if time_since_last >= self.reset_after:
             self.message_states[message_key] = {
@@ -91,7 +88,6 @@ class ThrottlingFilter(logging.Filter):
                 'current_interval': self.initial_throttle_interval
             }
             return True
-            
         if time_since_last >= state['current_interval']:
             # Message allowed - increase throttle interval for next occurrence
             next_interval = min(
@@ -103,5 +99,4 @@ class ThrottlingFilter(logging.Filter):
                 'current_interval': next_interval
             }
             return True
-        
         return False