forked from kytos/kytos
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #497 from kytos-ng/logging/filters
Add in log filter for pacing logs + bump version to 2024.1.1
- Loading branch information
Showing
7 changed files
with
182 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
The present metadata is intended to be used mainly on the setup. | ||
""" | ||
__version__ = '2024.1.0' | ||
__version__ = '2024.1.1' | ||
__author__ = 'Kytos Team' | ||
__author_email__ = '[email protected]' | ||
__license__ = 'MIT' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
|
||
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): | ||
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 = record.created | ||
with self._lock: | ||
if key not in self._cache: | ||
self._cache[key] = current_time | ||
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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
|
||
|
||
import unittest | ||
from logging import LogRecord | ||
|
||
import pytest | ||
|
||
from kytos.logging.filters import RepeateMessageFilter | ||
|
||
|
||
class TestRepeateMessageFilter: | ||
|
||
@pytest.fixture( | ||
params=[ | ||
1.0, | ||
5.0, | ||
10.0, | ||
] | ||
) | ||
def lockout_time(self, request): | ||
return request.param | ||
|
||
@pytest.fixture( | ||
params=[ | ||
1, | ||
256, | ||
512, | ||
1024, | ||
] | ||
) | ||
def cache_size(self, request): | ||
return request.param | ||
|
||
@pytest.fixture | ||
def message_filter(self, lockout_time, cache_size): | ||
return RepeateMessageFilter(lockout_time, cache_size) | ||
|
||
@staticmethod | ||
def make_record(msg, ct): | ||
record = LogRecord( | ||
"test_logger", | ||
0, | ||
"test_path", | ||
1337, | ||
msg, | ||
("arg1", "arg2"), | ||
None | ||
) | ||
record.created = ct | ||
record.relativeCreated = ct | ||
return record | ||
|
||
@pytest.fixture | ||
def blockable_record(self): | ||
return self.make_record("test", 0.0) | ||
|
||
@pytest.fixture | ||
def unblockable_record(self, lockout_time): | ||
return self.make_record("test", lockout_time + 1) | ||
|
||
@pytest.fixture | ||
def message_filter_with_one_message( | ||
self, | ||
message_filter, | ||
blockable_record | ||
): | ||
assert message_filter.filter(blockable_record) | ||
return message_filter | ||
|
||
@pytest.fixture | ||
def message_filter_with_one_message_and_junk( | ||
self, | ||
message_filter_with_one_message, | ||
cache_size | ||
): | ||
for i in range(cache_size - 1): | ||
assert message_filter_with_one_message.filter( | ||
self.make_record(f"junk-{i}", 0.0) | ||
) | ||
return message_filter_with_one_message | ||
|
||
@pytest.fixture | ||
def last_junk_record( | ||
self, | ||
cache_size | ||
): | ||
return self.make_record(f"junk-{cache_size - 1}", 0.0) | ||
|
||
def test_001_filter( | ||
self, | ||
message_filter_with_one_message, | ||
blockable_record, | ||
unblockable_record | ||
): | ||
assert not message_filter_with_one_message.filter(blockable_record) | ||
assert message_filter_with_one_message.filter(unblockable_record) | ||
assert not message_filter_with_one_message.filter(blockable_record) | ||
assert not message_filter_with_one_message.filter(unblockable_record) | ||
|
||
def test_002_cache_eviction( | ||
self, | ||
message_filter_with_one_message_and_junk, | ||
blockable_record, | ||
last_junk_record | ||
): | ||
assert not message_filter_with_one_message_and_junk.filter( | ||
blockable_record | ||
) | ||
assert message_filter_with_one_message_and_junk.filter( | ||
last_junk_record | ||
) | ||
assert message_filter_with_one_message_and_junk.filter( | ||
blockable_record | ||
) |