Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- opentelemetry-sdk: Added request filter which fixes invalid type at WSGI request headers and attributes
([#4808](https://github.com/open-telemetry/opentelemetry-python/pull/4808))
- docs: Added sqlcommenter example
([#4734](https://github.com/open-telemetry/opentelemetry-python/pull/4734))
- build: bump ruff to 0.14.1
Expand Down
9 changes: 4 additions & 5 deletions opentelemetry-api/src/opentelemetry/attributes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,7 @@ def _clean_extended_attribute_value(
# Freeze mutable sequences defensively
return tuple(cleaned_seq)

raise TypeError(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed this TypeError, because all objects with type other than AnyValue will have been converted to str.

f"Invalid type {type(value).__name__} for attribute value. "
f"Expected one of {[valid_type.__name__ for valid_type in _VALID_ANY_VALUE_TYPES]} or a "
"sequence of those types",
)
return value


def _clean_extended_attribute(
Expand Down Expand Up @@ -279,6 +275,9 @@ def __setitem__(self, key: str, value: types.AnyValue) -> None:
return

if self._extended_attributes:
# Convert types other than AnyValue to strings before cleaning
if not isinstance(value, _VALID_ANY_VALUE_TYPES):
value = str(value)
value = _clean_extended_attribute(
key, value, self.max_value_len
)
Expand Down
31 changes: 31 additions & 0 deletions opentelemetry-api/tests/attributes/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,34 @@ def test_extended_attributes(self):
bdict["key"] = "value"

clean_extended_attribute_mock.assert_called_once()

def test_wsgi_request_conversion_to_string(self):
"""Test that WSGI request objects are converted to strings before calling _clean_extended_attribute."""

class DummyWSGIRequest:
def __str__(self):
return "<DummyWSGIRequest method=GET path=/example/>"

bdict = BoundedAttributes(extended_attributes=True, immutable=False)
wsgi_request = DummyWSGIRequest()
original_request = wsgi_request # Keep reference to original object

with unittest.mock.patch(
"opentelemetry.attributes._clean_extended_attribute",
return_value="stringified_request",
) as clean_extended_attribute_mock:
bdict["request"] = wsgi_request

# Verify that _clean_extended_attribute was called
clean_extended_attribute_mock.assert_called_once()

# Verify that the value passed to _clean_extended_attribute is a string, not the original object
call_args = clean_extended_attribute_mock.call_args
passed_value = call_args[0][1] # Second argument is the value
self.assertIsInstance(passed_value, str)
self.assertNotEqual(
passed_value, original_request
) # Should be stringified, not the original object
self.assertIn(
"DummyWSGIRequest", passed_value
) # String representation includes class name