Skip to content

Commit fe73e6e

Browse files
author
Andrew Xue
committed
add check for event attribute values
1 parent c061d3c commit fe73e6e

File tree

2 files changed

+91
-40
lines changed

2 files changed

+91
-40
lines changed

Diff for: opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

+28-19
Original file line numberDiff line numberDiff line change
@@ -372,38 +372,39 @@ def set_attribute(self, key: str, value: types.AttributeValue) -> None:
372372
logger.warning("invalid key (empty or null)")
373373
return
374374

375-
if isinstance(value, Sequence):
376-
error_message = self._check_attribute_value_sequence(value)
377-
if error_message is not None:
378-
logger.warning("%s in attribute value sequence", error_message)
379-
return
380-
# Freeze mutable sequences defensively
381-
if isinstance(value, MutableSequence):
382-
value = tuple(value)
383-
elif not isinstance(value, (bool, str, int, float)):
384-
logger.warning("invalid type for attribute value")
375+
error_message = self._check_attribute_value(value)
376+
if error_message is not None:
377+
logger.warning(error_message)
385378
return
379+
# Freeze mutable sequences defensively
380+
if isinstance(value, MutableSequence):
381+
value = tuple(value)
386382

387383
self.attributes[key] = value
388384

389385
@staticmethod
390-
def _check_attribute_value_sequence(sequence: Sequence) -> Optional[str]:
386+
def _check_attribute_value(value: types.AttributeValue) -> Optional[str]:
391387
"""
392388
Checks if sequence items are valid and are of the same type
393389
"""
394-
if len(sequence) == 0:
395-
return None
390+
if isinstance(value, Sequence):
391+
if len(value) == 0:
392+
return None
396393

397-
first_element_type = type(sequence[0])
394+
first_element_type = type(value[0])
398395

399-
if first_element_type not in (bool, str, int, float):
400-
return "invalid type"
396+
if first_element_type not in (bool, str, int, float):
397+
return "invalid type in attribute value sequence"
401398

402-
for element in sequence:
403-
if not isinstance(element, first_element_type):
404-
return "different type"
399+
for element in value:
400+
if not isinstance(element, first_element_type):
401+
return "different types in attribute value sequence"
402+
return None
403+
elif not isinstance(value, (bool, str, int, float)):
404+
return "invalid type for attribute value"
405405
return None
406406

407+
407408
def _add_event(self, event: EventBase) -> None:
408409
with self._lock:
409410
if not self.is_recording_events():
@@ -425,6 +426,14 @@ def add_event(
425426
) -> None:
426427
if attributes is None:
427428
attributes = Span._empty_attributes
429+
else:
430+
for attr_key, attr_value in list(attributes.items()):
431+
error_message = self._check_attribute_value(attr_value)
432+
if error_message:
433+
logger.warning(error_message)
434+
return
435+
if isinstance(attr_value, MutableSequence):
436+
attributes[attr_key] = tuple(attr_value)
428437
self._add_event(
429438
Event(
430439
name=name,

Diff for: opentelemetry-sdk/tests/trace/test_trace.py

+63-21
Original file line numberDiff line numberDiff line change
@@ -487,39 +487,61 @@ def test_invalid_attribute_values(self):
487487

488488
self.assertEqual(len(root.attributes), 0)
489489

490-
def test_check_sequence_helper(self):
490+
def test_check_attribute_helper(self):
491491
# pylint: disable=protected-access
492492
self.assertEqual(
493-
trace.Span._check_attribute_value_sequence([1, 2, 3.4, "ss", 4]),
494-
"different type",
493+
trace.Span._check_attribute_value([1, 2, 3.4, "ss", 4]),
494+
"different types in attribute value sequence",
495495
)
496496
self.assertEqual(
497-
trace.Span._check_attribute_value_sequence([dict(), 1, 2, 3.4, 4]),
498-
"invalid type",
497+
trace.Span._check_attribute_value([dict(), 1, 2, 3.4, 4]),
498+
"invalid type in attribute value sequence",
499499
)
500500
self.assertEqual(
501-
trace.Span._check_attribute_value_sequence(
501+
trace.Span._check_attribute_value(
502502
["sw", "lf", 3.4, "ss"]
503503
),
504-
"different type",
504+
"different types in attribute value sequence",
505505
)
506506
self.assertEqual(
507-
trace.Span._check_attribute_value_sequence([1, 2, 3.4, 5]),
508-
"different type",
507+
trace.Span._check_attribute_value([1, 2, 3.4, 5]),
508+
"different types in attribute value sequence",
509509
)
510510
self.assertIsNone(
511-
trace.Span._check_attribute_value_sequence([1, 2, 3, 5])
511+
trace.Span._check_attribute_value([1, 2, 3, 5])
512512
)
513513
self.assertIsNone(
514-
trace.Span._check_attribute_value_sequence([1.2, 2.3, 3.4, 4.5])
514+
trace.Span._check_attribute_value([1.2, 2.3, 3.4, 4.5])
515515
)
516516
self.assertIsNone(
517-
trace.Span._check_attribute_value_sequence([True, False])
517+
trace.Span._check_attribute_value([True, False])
518518
)
519519
self.assertIsNone(
520-
trace.Span._check_attribute_value_sequence(["ss", "dw", "fw"])
520+
trace.Span._check_attribute_value(["ss", "dw", "fw"])
521+
)
522+
self.assertIsNone(
523+
trace.Span._check_attribute_value([])
524+
)
525+
526+
527+
self.assertEqual(
528+
trace.Span._check_attribute_value(dict()),
529+
"invalid type for attribute value",
530+
)
531+
self.assertIsNone(
532+
trace.Span._check_attribute_value(True)
533+
)
534+
self.assertIsNone(
535+
trace.Span._check_attribute_value('hi')
536+
)
537+
self.assertIsNone(
538+
trace.Span._check_attribute_value(3.4)
539+
)
540+
self.assertIsNone(
541+
trace.Span._check_attribute_value(15)
521542
)
522543

544+
523545
def test_sampling_attributes(self):
524546
decision_attributes = {
525547
"sampler-attr": "sample-val",
@@ -561,33 +583,52 @@ def test_events(self):
561583

562584
# event name and attributes
563585
now = time_ns()
564-
root.add_event("event1", {"name": "pluto"})
586+
root.add_event("event1", {"name": "pluto", "some_bools": [True, False]})
565587

566588
# event name, attributes and timestamp
567589
now = time_ns()
568-
root.add_event("event2", {"name": "birthday"}, now)
590+
root.add_event("event2", {"name": ["birthday"]}, now)
591+
592+
mutable_list = ["original_contents"]
593+
root.add_event("event3", {"name": mutable_list})
569594

570595
def event_formatter():
571596
return {"name": "hello"}
572597

573598
# lazy event
574-
root.add_lazy_event("event3", event_formatter, now)
599+
root.add_lazy_event("event4", event_formatter, now)
575600

576-
self.assertEqual(len(root.events), 4)
601+
self.assertEqual(len(root.events), 5)
577602

578603
self.assertEqual(root.events[0].name, "event0")
579604
self.assertEqual(root.events[0].attributes, {})
580605

581606
self.assertEqual(root.events[1].name, "event1")
582-
self.assertEqual(root.events[1].attributes, {"name": "pluto"})
607+
self.assertEqual(root.events[1].attributes, {"name": "pluto", "some_bools": (True, False)})
583608

584609
self.assertEqual(root.events[2].name, "event2")
585-
self.assertEqual(root.events[2].attributes, {"name": "birthday"})
610+
self.assertEqual(root.events[2].attributes, {"name": ("birthday",)})
586611
self.assertEqual(root.events[2].timestamp, now)
587612

588613
self.assertEqual(root.events[3].name, "event3")
589-
self.assertEqual(root.events[3].attributes, {"name": "hello"})
590-
self.assertEqual(root.events[3].timestamp, now)
614+
self.assertEqual(root.events[3].attributes, {"name": ("original_contents",)})
615+
mutable_list = ["new_contents"]
616+
self.assertEqual(root.events[3].attributes, {"name": ("original_contents",)})
617+
618+
self.assertEqual(root.events[4].name, "event4")
619+
self.assertEqual(root.events[4].attributes, {"name": "hello"})
620+
self.assertEqual(root.events[4].timestamp, now)
621+
622+
def test_invalid_event_attributes(self):
623+
self.assertIsNone(self.tracer.get_current_span())
624+
625+
with self.tracer.start_as_current_span("root") as root:
626+
root.add_event("event0", {"attr1": True, "attr2": ['hi', False]})
627+
root.add_event("event0", {"attr1": dict()})
628+
root.add_event("event0", {"attr1": [[True]]})
629+
root.add_event("event0", {"attr1": [dict()]})
630+
631+
self.assertEqual(len(root.events), 0)
591632

592633
def test_links(self):
593634
other_context1 = trace_api.SpanContext(
@@ -882,3 +923,4 @@ def test_add_span_processor_after_span_creation(self):
882923
expected_list.append(span_event_end_fmt("SP1", "foo"))
883924

884925
self.assertListEqual(spans_calls_list, expected_list)
926+

0 commit comments

Comments
 (0)