Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in log filter for pacing logs #497

Merged
merged 13 commits into from
Sep 5, 2024
9 changes: 8 additions & 1 deletion kytos/core/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,14 @@ def _patch_core_loggers():
reloadable_mods = [module for mod_name, module in sys.modules.items()
if mod_name[:str_len] == match_str]
for module in reloadable_mods:
module.LOG = logging.getLogger(module.__name__)
new_logger = logging.getLogger(module.__name__)
if hasattr(module, "LOG"):
old_logger = module.LOG
for handler in old_logger.handlers:
new_logger.addHandler(handler)
for log_filter in old_logger.filters:
new_logger.addFilter(log_filter)
module.LOG = new_logger

@staticmethod
def loggers():
Expand Down
4 changes: 4 additions & 0 deletions kytos/core/pacing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
from limits import RateLimitItem, parse
from limits.storage import storage_from_string

from kytos.logging.filters import RepeateMessageFilter

LOG = logging.getLogger(__name__)

LOG.addFilter(RepeateMessageFilter(1.0, 512))


class EmptyStrategy(limits.strategies.FixedWindowRateLimiter):
"""Rate limiter, that doesn't actually rate limit."""
Expand Down
47 changes: 47 additions & 0 deletions kytos/logging/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

import time
from collections import OrderedDict
from logging import LogRecord
from threading import Lock


class RepeateMessageFilter:
lockout_time: float
cache_size: int
_cache: OrderedDict[tuple, float]
_lock: Lock

def __init__(self, lockout_time: float, cache_size: int = 512):
viniarck marked this conversation as resolved.
Show resolved Hide resolved
self.lockout_time = lockout_time
self.cache_size = cache_size
self._cache = OrderedDict()
self._lock = Lock()

def filter(self, record: LogRecord) -> bool:
key = self._record_key(record)
current_time = time.time()
with self._lock:
if key not in self._cache:
self._cache[key] = current_time
self._cache.move_to_end(key)
viniarck marked this conversation as resolved.
Show resolved Hide resolved
if len(self._cache) > self.cache_size:
self._cache.popitem(last=False)
return True
elif current_time - self._cache[key] > self.lockout_time:
self._cache[key] = current_time
self._cache.move_to_end(key)
if len(self._cache) > self.cache_size:
self._cache.popitem(last=False)
return True
return False

@staticmethod
def _record_key(record: LogRecord):
return (
record.pathname,
record.module,
record.lineno,
record.levelno,
record.msg,
record.args
)
Loading