From da45d1c1eec9d5226b32042c2bc7025ef9851403 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 22:54:25 -0300 Subject: [PATCH 1/7] Allow bytes as attributes --- .../src/opentelemetry/attributes/__init__.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py index 724c931c826..a17985eaf9c 100644 --- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py +++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py @@ -21,8 +21,6 @@ from opentelemetry.util import types -# bytes are accepted as a user supplied value for attributes but -# decoded to strings internally. _VALID_ATTR_VALUE_TYPES = (bool, str, bytes, int, float) @@ -44,7 +42,6 @@ def _clean_attribute( An attribute needs cleansing if: - Its length is greater than the maximum allowed length. - - It needs to be encoded/decoded e.g, bytes to strings. """ if not (key and isinstance(key, str)): @@ -113,13 +110,6 @@ def _clean_attribute_value( if value is None: return None - if isinstance(value, bytes): - try: - value = value.decode() - except UnicodeDecodeError: - _logger.warning("Byte attribute could not be decoded.") - return None - if limit is not None and isinstance(value, str): value = value[:limit] return value From 948210f9bd89423de48b5fc3b54988615ed46319 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 22:59:13 -0300 Subject: [PATCH 2/7] edit some tests --- .../tests/resources/test_resources.py | 3 --- opentelemetry-sdk/tests/trace/test_trace.py | 16 ++++------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/opentelemetry-sdk/tests/resources/test_resources.py b/opentelemetry-sdk/tests/resources/test_resources.py index 53ecf30cab9..b3cfdf99f4f 100644 --- a/opentelemetry-sdk/tests/resources/test_resources.py +++ b/opentelemetry-sdk/tests/resources/test_resources.py @@ -237,9 +237,6 @@ def test_invalid_resource_attribute_values(self): { SERVICE_NAME: "test", "non-primitive-data-type": {}, - "invalid-byte-type-attribute": ( - b"\xd8\xe1\xb7\xeb\xa8\xe5 \xd2\xb7\xe1" - ), "": "empty-key-value", None: "null-key-value", "another-non-primitive": uuid.uuid4(), diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 4150d60d104..efd2777c34a 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -736,20 +736,12 @@ def test_invalid_attribute_values(self): def test_byte_type_attribute_value(self): with self.tracer.start_as_current_span("root") as root: - with self.assertLogs(level=WARNING): - root.set_attribute( - "invalid-byte-type-attribute", - b"\xd8\xe1\xb7\xeb\xa8\xe5 \xd2\xb7\xe1", - ) - self.assertFalse( - "invalid-byte-type-attribute" in root.attributes + for key, value in (("arbitrary", b"\xd8\xe1\xb7\xeb\xa8\xe5 \xd2\xb7\xe1"), ("encodable", b"valid byte")): + root.set_attribute(key, b"valid byte") + self.assertTrue( + isinstance(root.attributes[key], bytes) ) - root.set_attribute("valid-byte-type-attribute", b"valid byte") - self.assertTrue( - isinstance(root.attributes["valid-byte-type-attribute"], str) - ) - def test_sampling_attributes(self): sampling_attributes = { "sampler-attr": "sample-val", From 3cccbcd229fa2179da82bf88cce136bd16b00e9d Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 22:59:58 -0300 Subject: [PATCH 3/7] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f359c6b633f..89ea6750bd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Allow bytes as attributes + ([#3605](https://github.com/open-telemetry/opentelemetry-python/pull/3605)) + ## Version 1.22.0/0.43b0 (2023-12-15) - Prometheus exporter sanitize info metric ([#3572](https://github.com/open-telemetry/opentelemetry-python/pull/3572)) From 8be047137e581320f81beb79c1780f89c4365435 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:14:20 -0300 Subject: [PATCH 4/7] fix test --- opentelemetry-api/tests/attributes/test_attributes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/tests/attributes/test_attributes.py b/opentelemetry-api/tests/attributes/test_attributes.py index 121dec3d251..c3410e581d0 100644 --- a/opentelemetry-api/tests/attributes/test_attributes.py +++ b/opentelemetry-api/tests/attributes/test_attributes.py @@ -81,7 +81,7 @@ def test_sequence_attr_decode(self): None, "Content-Disposition", "Content-Type", - None, + b"\x81", "Keep-Alive", ] self.assertEqual( From 69384e22701e46b71d536fe125c10ec8bc299088 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:21:56 -0300 Subject: [PATCH 5/7] fix test --- opentelemetry-api/tests/attributes/test_attributes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/opentelemetry-api/tests/attributes/test_attributes.py b/opentelemetry-api/tests/attributes/test_attributes.py index c3410e581d0..5c984e6019f 100644 --- a/opentelemetry-api/tests/attributes/test_attributes.py +++ b/opentelemetry-api/tests/attributes/test_attributes.py @@ -79,10 +79,10 @@ def test_sequence_attr_decode(self): ] expected = [ None, - "Content-Disposition", - "Content-Type", + b"Content-Disposition", + b"Content-Type", b"\x81", - "Keep-Alive", + b"Keep-Alive", ] self.assertEqual( _clean_attribute("headers", seq, None), tuple(expected) From ed306ac4a4b352ee5158d76253ac2139cdbc8186 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:28:44 -0300 Subject: [PATCH 6/7] lint --- opentelemetry-sdk/tests/trace/test_trace.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index efd2777c34a..3f0323ff03a 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -736,11 +736,12 @@ def test_invalid_attribute_values(self): def test_byte_type_attribute_value(self): with self.tracer.start_as_current_span("root") as root: - for key, value in (("arbitrary", b"\xd8\xe1\xb7\xeb\xa8\xe5 \xd2\xb7\xe1"), ("encodable", b"valid byte")): + for key, value in ( + ("arbitrary", b"\xd8\xe1\xb7\xeb\xa8\xe5 \xd2\xb7\xe1"), + ("encodable", b"valid byte"), + ): root.set_attribute(key, b"valid byte") - self.assertTrue( - isinstance(root.attributes[key], bytes) - ) + self.assertTrue(isinstance(root.attributes[key], bytes)) def test_sampling_attributes(self): sampling_attributes = { From 9648e02b040f6cfce6c9ba4efa05bfc7740b5aa3 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Sat, 30 Dec 2023 16:48:03 -0300 Subject: [PATCH 7/7] Handle bytes in OTLP exporter --- .../exporter/otlp/proto/common/_internal/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/__init__.py b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/__init__.py index bd6ca4ad180..3c9c78a11f9 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/__init__.py +++ b/exporter/opentelemetry-exporter-otlp-proto-common/src/opentelemetry/exporter/otlp/proto/common/_internal/__init__.py @@ -68,6 +68,8 @@ def _encode_value(value: Any) -> PB2AnyValue: return PB2AnyValue(int_value=value) if isinstance(value, float): return PB2AnyValue(double_value=value) + if isinstance(value, bytes): + return PB2AnyValue(bytes_value=value) if isinstance(value, Sequence): return PB2AnyValue( array_value=PB2ArrayValue(values=[_encode_value(v) for v in value])