Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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(
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