Skip to content

Commit 9850fb3

Browse files
sdk: Improve attributes validation (#460)
4fca8c9 ("Add runtime validation in setAttribute (#348)") added a robust attribute validation using numbers.Number to validate numeric types. Although the approach is correct, it presents some complications because Complex, Fraction and Decimal are accepted because they are Numbers. This presents a problem to the exporters because they will have to consider all these different cases when converting attributes to the underlying exporter representation. This commit simplifies the logic by accepting only int and float as numeric values.
1 parent d7d9b15 commit 9850fb3

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import random
1919
import threading
2020
from contextlib import contextmanager
21-
from numbers import Number
2221
from types import TracebackType
2322
from typing import Iterator, Optional, Sequence, Tuple, Type
2423

@@ -234,12 +233,16 @@ def set_attribute(self, key: str, value: types.AttributeValue) -> None:
234233
logger.warning("Setting attribute on ended span.")
235234
return
236235

236+
if not key:
237+
logger.warning("invalid key (empty or null)")
238+
return
239+
237240
if isinstance(value, Sequence):
238241
error_message = self._check_attribute_value_sequence(value)
239242
if error_message is not None:
240243
logger.warning("%s in attribute value sequence", error_message)
241244
return
242-
elif not isinstance(value, (bool, str, Number, Sequence)):
245+
elif not isinstance(value, (bool, str, int, float)):
243246
logger.warning("invalid type for attribute value")
244247
return
245248

@@ -255,10 +258,7 @@ def _check_attribute_value_sequence(sequence: Sequence) -> Optional[str]:
255258

256259
first_element_type = type(sequence[0])
257260

258-
if issubclass(first_element_type, Number):
259-
first_element_type = Number
260-
261-
if first_element_type not in (bool, str, Number):
261+
if first_element_type not in (bool, str, int, float):
262262
return "invalid type"
263263

264264
for element in sequence:

opentelemetry-sdk/tests/trace/test_trace.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ def test_attributes(self):
405405

406406
root.set_attribute("empty-list", [])
407407
root.set_attribute("list-of-bools", [True, True, False])
408-
root.set_attribute("list-of-numerics", [123, 3.14, 0])
408+
root.set_attribute("list-of-numerics", [123, 314, 0])
409409

410410
self.assertEqual(len(root.attributes), 10)
411411
self.assertEqual(root.attributes["component"], "http")
@@ -423,7 +423,7 @@ def test_attributes(self):
423423
root.attributes["list-of-bools"], [True, True, False]
424424
)
425425
self.assertEqual(
426-
root.attributes["list-of-numerics"], [123, 3.14, 0]
426+
root.attributes["list-of-numerics"], [123, 314, 0]
427427
)
428428

429429
attributes = {
@@ -454,6 +454,9 @@ def test_invalid_attribute_values(self):
454454
"list-with-non-primitive-data-type", [dict(), 123]
455455
)
456456

457+
root.set_attribute("", 123)
458+
root.set_attribute(None, 123)
459+
457460
self.assertEqual(len(root.attributes), 0)
458461

459462
def test_check_sequence_helper(self):
@@ -472,8 +475,18 @@ def test_check_sequence_helper(self):
472475
),
473476
"different type",
474477
)
478+
self.assertEqual(
479+
trace.Span._check_attribute_value_sequence([1, 2, 3.4, 5]),
480+
"different type",
481+
)
482+
self.assertIsNone(
483+
trace.Span._check_attribute_value_sequence([1, 2, 3, 5])
484+
)
485+
self.assertIsNone(
486+
trace.Span._check_attribute_value_sequence([1.2, 2.3, 3.4, 4.5])
487+
)
475488
self.assertIsNone(
476-
trace.Span._check_attribute_value_sequence([1, 2, 3.4, 5])
489+
trace.Span._check_attribute_value_sequence([True, False])
477490
)
478491
self.assertIsNone(
479492
trace.Span._check_attribute_value_sequence(["ss", "dw", "fw"])

0 commit comments

Comments
 (0)