diff --git a/aws_xray_sdk/core/utils/conversion.py b/aws_xray_sdk/core/utils/conversion.py index 0f15430f..f190726c 100644 --- a/aws_xray_sdk/core/utils/conversion.py +++ b/aws_xray_sdk/core/utils/conversion.py @@ -1,3 +1,4 @@ +from collections.abc import Iterable import logging log = logging.getLogger(__name__) @@ -17,12 +18,15 @@ def metadata_to_dict(obj): return str(obj) elif hasattr(obj, "_ast"): return metadata_to_dict(obj._ast()) - elif hasattr(obj, "__iter__") and not isinstance(obj, str): - metadata = [] - for item in obj: - metadata.append(metadata_to_dict(item)) - return metadata - elif hasattr(obj, "__dict__"): + elif isinstance(obj, Iterable) and not isinstance(obj, str): + try: + metadata = [] + for item in obj: + metadata.append(metadata_to_dict(item)) + return metadata + except TypeError: + pass + if hasattr(obj, "__dict__"): metadata = {} for key, value in vars(obj).items(): if not callable(value) and not key.startswith('_'): diff --git a/tests/test_utils.py b/tests/test_utils.py index 9c35ad84..b803cdb9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -92,4 +92,46 @@ def test_inject_trace_header_sampled(): inject_trace_header(headers, subsegment) - assert 'Sampled=1' in headers['X-Amzn-Trace-Id'] \ No newline at end of file + assert 'Sampled=1' in headers['X-Amzn-Trace-Id'] + +def test_metadata_to_dict_non_iterable_object(): + from aws_xray_sdk.core.utils.conversion import metadata_to_dict + + class MockMySQLConnection: + __iter__ = None + + def __init__(self): + self.host = "localhost" + self.port = 3306 + self._secret = "hidden" + + conn = MockMySQLConnection() + result = metadata_to_dict(conn) + assert result == {"host": "localhost", "port": 3306} + + +def test_metadata_to_dict_broken_iterable(): + from aws_xray_sdk.core.utils.conversion import metadata_to_dict + + class BrokenIterable: + def __iter__(self): + raise TypeError("iteration failed") + + def __init__(self): + self.status = "active" + self._private = 123 + + obj = BrokenIterable() + result = metadata_to_dict(obj) + assert result == {"status": "active"} + + +def test_metadata_to_dict_collection_types(): + from aws_xray_sdk.core.utils.conversion import metadata_to_dict + + assert metadata_to_dict({"k": "v"}) == {"k": "v"} + assert metadata_to_dict([1, "a", True]) == [1, "a", True] + assert metadata_to_dict((1, 2)) == [1, 2] + assert metadata_to_dict("text") == "text" + assert metadata_to_dict(42) == 42 + assert metadata_to_dict(None) is None