diff --git a/logtail/frame.py b/logtail/frame.py index 8d730b5..919ed5c 100644 --- a/logtail/frame.py +++ b/logtail/frame.py @@ -60,23 +60,28 @@ def _parse_custom_events(record, include_extra_attributes): def _remove_circular_dependencies(obj, memo=None): if memo is None: memo = set() + # Skip immutable types, which can't contain circular dependencies - if isinstance(obj, (str, int, float, bool)): + if isinstance(obj, (str, int, float, bool, type(None))): return obj - if id(obj) in memo: + + # For mutable objects, check for circular references + obj_id = id(obj) + if obj_id in memo: return "" - memo.add(id(obj)) + memo.add(obj_id) + if isinstance(obj, dict): new_dict = {} for key, value in obj.items(): - new_dict[key] = _remove_circular_dependencies(value, memo) + new_dict[key] = _remove_circular_dependencies(value, memo.copy()) return new_dict elif isinstance(obj, list): - return [_remove_circular_dependencies(item, memo) for item in obj] + return [_remove_circular_dependencies(item, memo.copy()) for item in obj] elif isinstance(obj, tuple): - return tuple(_remove_circular_dependencies(item, memo) for item in obj) + return tuple(_remove_circular_dependencies(item, memo.copy()) for item in obj) elif isinstance(obj, set): - return {_remove_circular_dependencies(item, memo) for item in obj} + return {_remove_circular_dependencies(item, memo.copy()) for item in obj} else: return obj diff --git a/tests/test_handler.py b/tests/test_handler.py index bd10255..c8d860d 100644 --- a/tests/test_handler.py +++ b/tests/test_handler.py @@ -224,6 +224,27 @@ def test_can_have_multiple_instance_of_same_string_in_extra_data(self, MockWorke self.assertEqual(log_entry['test2'], 'this is a test string') self.assertTrue(handler.pipe.empty()) + @patch('logtail.handler.FlushWorker') + def test_can_have_multiple_instance_of_same_array_in_extra_data(self, MockWorker): + buffer_capacity = 1 + handler = LogtailHandler( + source_token=self.source_token, + buffer_capacity=buffer_capacity + ) + + logger = logging.getLogger(__name__) + logger.handlers = [] + logger.addHandler(handler) + test_array = ['this is a test string'] + logger.info('hello', extra={'test1': test_array, 'test2': test_array}) + + log_entry = handler.pipe.get() + + self.assertEqual(log_entry['message'], 'hello') + self.assertEqual(log_entry['test1'], ['this is a test string']) + self.assertEqual(log_entry['test2'], ['this is a test string']) + self.assertTrue(handler.pipe.empty()) + @patch('logtail.handler.FlushWorker') def test_can_send_circular_dependency_in_context(self, MockWorker): buffer_capacity = 1