|
|
@@ -30,42 +30,69 @@ class LoggerSingleton:
|
|
|
backupCount=log_config['backup_count']
|
|
|
)
|
|
|
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
|
- file_handler.addFilter(ThrottlingFilter(throttle_interval=1.0))
|
|
|
+ file_handler.addFilter(ThrottlingFilter())
|
|
|
file_handler.setFormatter(file_formatter)
|
|
|
logger.addHandler(file_handler)
|
|
|
|
|
|
if log_config['console_output']:
|
|
|
console_handler = logging.StreamHandler()
|
|
|
- console_handler.addFilter(ThrottlingFilter(throttle_interval=1.0))
|
|
|
+ console_handler.addFilter(ThrottlingFilter())
|
|
|
console_formatter = logging.Formatter('%(levelname)s: %(message)s')
|
|
|
console_handler.setFormatter(console_formatter)
|
|
|
logger.addHandler(console_handler)
|
|
|
|
|
|
return logger
|
|
|
-
|
|
|
- import logging
|
|
|
-import time
|
|
|
+
|
|
|
|
|
|
class ThrottlingFilter(logging.Filter):
|
|
|
- def __init__(self, name='', throttle_interval=10.0):
|
|
|
+ def __init__(self, name='', initial_throttle_interval=1.0, max_throttle_interval=120.0,
|
|
|
+ throttle_multiplier=2.0, reset_after=120.0):
|
|
|
"""
|
|
|
:param name: Filter name (can be left empty)
|
|
|
- :param throttle_interval: Time interval (in seconds) that must pass before a duplicate message is logged.
|
|
|
+ :param initial_throttle_interval: Initial time interval (in seconds) before allowing duplicate messages
|
|
|
+ :param max_throttle_interval: Maximum throttle interval (in seconds)
|
|
|
+ :param throttle_multiplier: Factor by which to increase the interval for repeated messages
|
|
|
+ :param reset_after: Time in seconds after which to reset throttle interval if message wasn't seen
|
|
|
"""
|
|
|
super().__init__(name)
|
|
|
- self.throttle_interval = throttle_interval
|
|
|
- # A dictionary to store the last logged time for each unique message
|
|
|
- self.last_logged = {}
|
|
|
+ self.initial_throttle_interval = initial_throttle_interval
|
|
|
+ self.max_throttle_interval = max_throttle_interval
|
|
|
+ self.throttle_multiplier = throttle_multiplier
|
|
|
+ self.reset_after = reset_after
|
|
|
+ self.message_states = {}
|
|
|
|
|
|
def filter(self, record):
|
|
|
current_time = time.time()
|
|
|
- # Use the log message as a key. For more complex scenarios, you could combine
|
|
|
- # other record attributes like record.levelno, record.name, etc.
|
|
|
message_key = record.getMessage()
|
|
|
- last_time = self.last_logged.get(message_key, 0)
|
|
|
|
|
|
- if current_time - last_time >= self.throttle_interval:
|
|
|
- self.last_logged[message_key] = current_time
|
|
|
- return True # Allow the record to be logged
|
|
|
- else:
|
|
|
- return False # Skip logging this record
|
|
|
+ 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] = {
|
|
|
+ 'last_time': current_time,
|
|
|
+ '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(
|
|
|
+ state['current_interval'] * self.throttle_multiplier,
|
|
|
+ self.max_throttle_interval
|
|
|
+ )
|
|
|
+ self.message_states[message_key] = {
|
|
|
+ 'last_time': current_time,
|
|
|
+ 'current_interval': next_interval
|
|
|
+ }
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|