Skip to content

Commit cb660cf

Browse files
authored
Improve omitting circular references (#30)
1 parent 31dbb39 commit cb660cf

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

logtail/frame.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,28 @@ def _parse_custom_events(record, include_extra_attributes):
6060
def _remove_circular_dependencies(obj, memo=None):
6161
if memo is None:
6262
memo = set()
63+
6364
# Skip immutable types, which can't contain circular dependencies
64-
if isinstance(obj, (str, int, float, bool)):
65+
if isinstance(obj, (str, int, float, bool, type(None))):
6566
return obj
66-
if id(obj) in memo:
67+
68+
# For mutable objects, check for circular references
69+
obj_id = id(obj)
70+
if obj_id in memo:
6771
return "<omitted circular reference>"
68-
memo.add(id(obj))
72+
memo.add(obj_id)
73+
6974
if isinstance(obj, dict):
7075
new_dict = {}
7176
for key, value in obj.items():
72-
new_dict[key] = _remove_circular_dependencies(value, memo)
77+
new_dict[key] = _remove_circular_dependencies(value, memo.copy())
7378
return new_dict
7479
elif isinstance(obj, list):
75-
return [_remove_circular_dependencies(item, memo) for item in obj]
80+
return [_remove_circular_dependencies(item, memo.copy()) for item in obj]
7681
elif isinstance(obj, tuple):
77-
return tuple(_remove_circular_dependencies(item, memo) for item in obj)
82+
return tuple(_remove_circular_dependencies(item, memo.copy()) for item in obj)
7883
elif isinstance(obj, set):
79-
return {_remove_circular_dependencies(item, memo) for item in obj}
84+
return {_remove_circular_dependencies(item, memo.copy()) for item in obj}
8085
else:
8186
return obj
8287

tests/test_handler.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,27 @@ def test_can_have_multiple_instance_of_same_string_in_extra_data(self, MockWorke
224224
self.assertEqual(log_entry['test2'], 'this is a test string')
225225
self.assertTrue(handler.pipe.empty())
226226

227+
@patch('logtail.handler.FlushWorker')
228+
def test_can_have_multiple_instance_of_same_array_in_extra_data(self, MockWorker):
229+
buffer_capacity = 1
230+
handler = LogtailHandler(
231+
source_token=self.source_token,
232+
buffer_capacity=buffer_capacity
233+
)
234+
235+
logger = logging.getLogger(__name__)
236+
logger.handlers = []
237+
logger.addHandler(handler)
238+
test_array = ['this is a test string']
239+
logger.info('hello', extra={'test1': test_array, 'test2': test_array})
240+
241+
log_entry = handler.pipe.get()
242+
243+
self.assertEqual(log_entry['message'], 'hello')
244+
self.assertEqual(log_entry['test1'], ['this is a test string'])
245+
self.assertEqual(log_entry['test2'], ['this is a test string'])
246+
self.assertTrue(handler.pipe.empty())
247+
227248
@patch('logtail.handler.FlushWorker')
228249
def test_can_send_circular_dependency_in_context(self, MockWorker):
229250
buffer_capacity = 1

0 commit comments

Comments
 (0)